vue3 setup emit with function click - vuejs3

i want to run a method when emitting how can i get it?
When handleShow(depth is clicked), I want to run collapsed in the medhod in the setup.
or
I want to trigger the function I will write in setup
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
methods: {
collapsed(dep) {
console.log(dep)
}
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
emit('clicked', depth)
}
return {
showDropdown,
handleShow,
}
},
};
</script>

emit should only be used if you want to get an event out of your component to its parent (for example, if your component is a custom button and you want its parent to specify what would happen when clicking on it). Otherwise, you can write the code you want inside of handleShow instead of calling emit. You can also change the function name to whatever you want, just make sure it's the same inside the setup method and in the #click.stop property.
In your case (since you just console.log the result):
<MenuLink
:link="items"
:key="items.title"
#click.stop="handleShow(depth)"
/>
<script>
import {ref} from "vue"
import MenuLink from "./MenuLink";
export default {
name: 'MenuItems',
components: {MenuLink},
props: {
items: {type: Object, required: true},
depth: {Number},
selected: {Number},
},
data() {
return {
opensCollapsed: false
};
},
setup(props, {emit}) {
const showDropdown = ref(false);
const handleShow = (depth) => {
console.log(depth)
// do whatever you want here
}
return {
showDropdown,
handleShow,
}
},
};
</script>

Related

Storybook Vue3 - Work with v-model in stories

I have a question regarding Storybook and Vue components with v-models. When writing a story for let's say an input component with a v-model i want a control reflecting the value of this v-model. Setting the modelValue from the control is no problem, but when using the component itself the control value stays the same. I am searching the web for a while now but i can't seem to find a solution for this.
A small example:
// InputComponent.vue
<template>
<input
type="text"
:value="modelValue"
#input="updateValue"
:class="`form-control${readonly ? '-plaintext' : ''}`"
:readonly="readonly"
/>
</template>
<script lang="ts">
export default {
name: "GcInputText"
}
</script>
<script lang="ts" setup>
defineProps({
modelValue: {
type: String,
default: null
},
readonly: {
type: Boolean,
default: false
}
});
const emit = defineEmits(['update:modelValue']);
const updateValue = (event: Event) => {
const target = event.target as HTMLInputElement;
emit('update:modelValue', target.value);
}
</script>
In Storybook:
Does anyone have a solution to make this working?
Thanks in advance!
In my case, I have a custom select input that uses a modelValue prop.
I tried this and worked for me:
at my-component.stories.js:
import { ref } from 'vue'
import MyComponent from './MyComponent.vue'
export default {
title: 'Core/MyComponent',
component: MyComponent,
argTypes: { }
}
const Template = (args) => ({
components: { MyComponent },
setup() {
let model = ref('Javascript')
const updateModel = (event) => model.value = event
return { args, model, updateModel }
},
template: '<my-component v-bind="args" :modelValue="model" #update:modelValue="updateModel" />'
})
export const Default = Template.bind({})
Default.args = {
options: [
'Javascript',
'PHP',
'Java'
]
}

Vue3 Props v-if sync

I'm making props with vue, but v-if doesn't work, and I'm wondering if the functions I've done are written correctly.
I want the data from props to work synchronously. What are my mistakes made?
What functions does vue props check at startup?
<my-alert type="warning" appearance="outline" showIcon="false">Hello</my-alert>
myAlert.vue
<template>
<div class="block" :class="[typeClass,appearanceClass]">
<div class="alert-icon" v-if="myIcon">
<i>ICON</i>
</div>
</div>
</template>
<script>
const types =
['primary','accent','warn','basic','info','success','warning','error',
];
const appearances =
['border','accent','fill','outline','soft'];
import {defineComponent} from "vue";
import {computed} from "vue";
export default {
props: {
type: {
type: String,
default: 'primary',
required: true,
validator: value => {
return ['primary', 'accent', 'warn', 'basic', 'info', 'success', 'warning', 'error'].includes(value)
}
},
appearance: {
type: String,
default: 'border',
required: true,
validator: value => {
return ['border', 'accent', 'fill', 'outline', 'soft'].includes(value)
}
},
showIcon: {
default: false
}
},
computed: {
typeClass() {
return 'alert-type-' + this.type
},
appearanceClass() {
return 'alert-appearance-' + this.appearance
},
myIcon() {
return this.showIcon;
}
}
}
</script>
From your code what I can see, that you are passing the props shwoIcon like this showIcon="false", which is static passing and eventually pass false value as a string "false" not as Boolean value. So use props like this :shwoIcon="false" I mean use colon before showIcon which make the props dynamic. link
And Also in your my-alert component for showIcon props declear type for the better practice
showIcon: {
type: Boolean,
default: false,
},
Another way is, just simply change your computed property myIcon() to check the string props value, like this below,
myIcon() {
return this.showIcon === "true";
}

NextJS: getServerSideProps - Is there a problem to use props object with redirect in the same return?

I'm using Next.js with Typescript, and I'm having some troubles to correctly type my props that getServerSideProps would return me. On getServerSideProps, or as I call it, getServerSidePropsImpl, I check user authentication and decide if I give it a redirect or the data for it to initialize. The problem with this is that Typescript doesn't correctly type my props, or give me some errors.
So, i had the idea to :
// /pages/sheet/1.tsx
import React from 'react';
import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next';
import database from '../../utils/database';
import { sessionSSR } from '../../utils/session';
export default function Sheet1(props: InferGetServerSidePropsType<typeof getServerSidePropsImpl>): JSX.Element {
//...Do some stuff...
return <></>;
}
async function getServerSidePropsImpl(ctx: GetServerSidePropsContext) {
const player = ctx.req.session.player;
if (!player) {
return {
redirect: {
destination: '/',
permanent: false
},
props: {
playerID: 0,
playerInfo: []
}
};
}
const playerID = player.id;
const results = await Promise.all([
database.playerInfo.findMany({
where: {
player_id: playerID
},
select: {
info: true,
value: true
},
})
]);
return {
props: {
playerID,
playerInfo: results[0]
}
};
}
export const getServerSideProps = sessionSSR(getServerSidePropsImpl);
To make sure Typescript would correctly type my props object, I had to put generic values when returning a redirect:
return {
redirect: {
destination: '/',
permanent: false
},
props: {
playerID: 0,
playerInfo: []
}
};
Is there any issues to this approach, giving the amount of props will increase as I make this component?

Vue 3 compoition API computed function

Trying to switch my code to the new composition API that comes with Vue 3 but I cant get it to work.
export default {
props: {
classProp: {type: String},
error: {type: String},
},
setup(){
// move to here (this is not working)
computed(() => {
const classObject = () => {
return ['form__control', this.classProp,
{
'form__invalid': this.error
}
]
}
})
},
computed: {
classObject: function () {
return ['form__control', this.classProp,
{
'form__invalid': this.error
}
]
}
},
}
skip "computed" all together
you need to use "ref" or "reactive". these are modules:
<script>
import { ref } from 'vue'
setup(){
const whateverObject = ref({ prop: "whatever initial value" });
whateverObject.value.prop= "if you change something within setup you need to access it trough .value";
return { whateverObject } // expose it to the template by returning it
}
</script>
if you want to use classes you import them like in this example of my own:
import { APIBroker } from '~/helpers/APIbroker'
const api = new APIBroker({})
Now "api" can be used inside setup() or wherever

Vuex, Vuexfire: How to get data from firestore into frontend?

I have some data in a firestore and want to display it in my vue app.
Firestore:
Test.vue
<template>
<p>{{ items }}</p>
</template>
<script>
import { mapState } from "vuex";
export default {
computed: mapState(["items"]),
methods: {
getItems() {
this.$store.dispatch("bindItems");
},
},
mounted() {
this.getItems();
},
};
</script>
index.js
import { createStore } from "vuex";
import { firestoreAction } from "vuexfire";
import { vuexfireMutations } from "vuexfire";
import { db } from "./db";
const store = createStore({
state() {
return {
items: [],
};
},
actions: {
bindItems: firestoreAction(({ bindFirestoreRef }) => {
return bindFirestoreRef("items", db.collection("items"));
}),
},
mutations: {
...vuexfireMutations,
},
getters: {
items(state) {
return state.items;
},
},
});
store.subscribe((state) => console.log(state));
export default store;
To check my store, I added this line in index.js: store.subscribe((state) => console.log(state));. As it turns out, the data from firestore actually makes it to my store:
Why is it not rendered in the frontend? What do I have to change to make it appear?
Edit.
When I hardcode some data in my store and remove this.$store.dispatch("bisndItems"); from the monuted hook, the data gets rendered:
state() {
return {
items: {"name": "peter"},
};
},

Resources