Passing function as prop in Vuejs is not working - vue.js

I'm trying to create a custom selector that I ill reuse several times and I want to set a prop to the function it has to trigger when a selection is made. Here is my code (only the relevant parts of it):
Main Selector:
<template>
<div>
<select name="selector" >
<option :key="option" v-for="option in options" #change="selection"> {{option}} </option>
</select>
</div>
</template>
<script>
export default {
name: 'CoffeeSelector',
props: {
options: Array,
selection: Function
},
}
</script>
The page where I use it:
<template>
<div>
<custom-selector :options='types' :selection="coucou"> </custom-selector>
</div>
</template>
<script>
import CustomSelector from './CustomSelector.vue'
export default {
name: 'Selectors',
components: {
CustomSelector
},
methods: {
coucou(){
console.log("coucou")
}
}
}
</script>
When I do this, nothing happens when I change the selection. Any ideas on why it happens? Thanks in advance

You can emit events to the parent component.
<template>
<div>
<select name="selector" >
<option :key="option" v-for="option in options" #change="onOptionChange(option)"> {{option}} </option>
</select>
</div>
</template>
<script>
export default {
name: 'CoffeeSelector',
props: {
options: Array
},
methods: {
onOptionChange(option) {
this.$emit('selection', option);
}
}
}
</script>
Then you can listen to those events within the parent component.
<template>
<div>
<custom-selector :options='types' v-on:selection="coucou"> </custom-selector>
</div>
</template>
<script>
import CustomSelector from './CustomSelector.vue'
export default {
name: 'Selectors',
components: {
CustomSelector
},
methods: {
coucou(option){
console.log("coucou: " + option)
}
}
}
</script>

try moving your #change to the select tag instead
<select name="selector" #change="selection">
<option :key="option" v-for="option in options"> {{option}} </option>
</select>

Related

VUE, Can't use selected option value in a select component

Im trying to use a selected option value. Can't show the value or save it.
This is my child component
`
<script>
export default {
props: {
options : {
type:Array,
},
selectOpt:undefined,
}
emits : ['input','change','option:selected']
}
</script>
<template>
<div>
<h1>
Hi, I'm a component
</h1>
<select
v-model="selectOpt"
#change="$emit('input', event.target.value)">
<option v-for="option in options"
:key="option"
>{{option}}</option>
</select>
</div>
</template>
`
This is my parent
`
<script >
import Comp from './Comp.vue'
export default {
data() {
return {
options : [1,2,3,4,5,6],
optSelected : undefined,
}
},
components: {
Comp
}
}
</script>
<template>
<Comp v-model="optSelected" :options="options"></Comp>
<p>
--->{{optSelected}}
</p>
</template>
`
I tried changin the 'input' event and 'change' event. not sure what im doing wrong.
i've found a solution that requires a vue-select library that i prefer not to use.
It's a simple detail: in vue 3, you need to use update:modelValue in order to change the v-model in parent component. (Reference: https://v3-migration.vuejs.org/breaking-changes/v-model.html)
And another thing: you souldn't use the prop as a v-model to prevent side effects in your application. You can read more about it here: https://eslint.vuejs.org/rules/no-mutating-props.html
Hope it helps:
<script>
export default {
props: {
options: {
type: Array
},
modelValue: undefined
},
emits: ['update:modelValue'],
watch: {
innerValue(newValue) {
this.$emit('update:modelValue', newValue)
},
modelValue(newValue) {
this.innerValue = newValue;
}
},
data() {
return {
innerValue: this.modelValue
};
}
};
</script>
<template>
<div>
<h1>Hi, I'm a component</h1>
<select v-model="innerValue">
<option v-for="option in options" :key="option">
{{ option }}
</option>
</select>
</div>
</template>
[Edit] Using Fallthrough Attribute:
You can use the v-bind="$atrrs":
<script>
export default {
props: {
options: {
type: Array
},
},
};
</script>
<template>
<div>
<h1>Hi, I'm a component</h1>
<select v-bind="$attrs">
<option v-for="option in options" :key="option">
{{ option }}
</option>
</select>
</div>
</template>
Read more: https://vuejs.org/guide/components/attrs.html#attribute-inheritance-on-multiple-root-nodes

Save selected values of input despite switching between two components in VUEJS

So I have two components that are imported into my app.vue:
<script>
import Leaderboard from "./components/Comp1.vue";
import Search from "./components/Comp2.vue";
export default {
name: "App",
components: {
Comp1,
Comp2,
},
}
These components are called, when I click on the corresponding button. This all works fine.
But in the components I have some input fields such as in Comp1.vue:
<template>
<div>
<select
class="form-select"
name="event"
id=""
v-model="selectedEvent"
>
<option value="">Please choose an event:</option>
<option v-for="event in eventsList" :key="event">
{{ event }}
</option>
</select>
</div>
</template>
<script>
data: function () {
return {
selectedEvent: "",
</script>
Here I can choose, which event to watch. But after switching to Comp2 and then again choosing Comp1, the selectedEvent is empty. Obviously, because its defined empty in data.
Is there any way to store the selected value in a session variable or would you prefer a different technique?
UI looks like this:
You can maintain an Object in your parent which you can pass as props to a props and then have a two way handshake
<Leaderboard :formInputs="formInputs"></Leaderboard>
<script>
import Leaderboard from "./components/Comp1.vue";
import Search from "./components/Comp2.vue";
export default {
name: "App",
components: {
Comp1,
Comp2,
},
data() {
return {
formInputs: {
compOneInput: '',
compTwpInput: ''
}
},
methods: {
updateData(payload) {
this.formInputs[payload.key] = payload.value;
}
}
and then pass this formInputs to your child Component from where you
you can emit the change whenever you update the input inside that
<template>
<div>
<select
class="form-select"
name="event"
id=""
v-model="selectedEvent"
>
<option value="">Please choose an event:</option>
<option v-for="event in eventsList" :key="event">
{{ event }}
</option>
</select>
</div>
</template>
<script>
export default {
data: function () {
return {
selectedEvent: this.formInputs.compOneInput ? this.formInputs.compOneInput : '',
}
},
watch: {
formInputs(newVal) {
this.selectedEvent = newVal.compOneInput;
},
selectedEvent(newVal, oldVal) {
if(newVal !== oldVal) {
this.$emit('updateData', {key: compOneInput, value: this.selectedEvent});
}
}
}
props: {
formInputs: Object
}
}
</script>
Using the above example for component one , you can implement the same for component two also
you can add a watcher on selectedEvent then store the data in vuex store

Unable to register custom component globally with vue.js

I have made selectbox component and wants to reuse it in other components. Si I want to register that component globally. I have imported that component in main.js but doesnot works.
main.js
import Selectbox from "#/modules/Selectbox.vue";
Vue.component("Selectbox", Selectbox);
Selectbox.vue
<template>
<div>
<label>{{ label }}</label>
<select #change="$emit('input', $event.target.value)">
<option
v-for="opt in options"
:key="opt.value"
:value="opt.value"
:selected="value === opt.value"
>
{{ errorMessage }}
{{ opt.label || "No label" }}
</option>
</select>
</div>
</template>
<script>
export default {
props: {
label: {
type: String,
required: true
},
},
data() {
return {
errorMessage: "",
option: "lorem",
options: [
{ label: "lorem", value: "lorem" },
{ label: "ipsum", value: "ipsum" }
]
};
},
};
</script>
Test.vue
<template>
<div>
<Selectbox v-model="ward_no"/>
</div>
</template>
<script>
export default {
data() {
return {
ward_no: '',
};
}
}
</script>
There is nothing wrong in the way that you are trying to register global component but you are missing script tag.
UPDATE: After talking to #prabinasht on skype and reviewing her code, I saw that in multiple files she forgot to remove locally imported/registered component and at the same time the component was registered globally too, so that was the problem.
Register the component this way
Vue.component('Selectbox', require('#/modules/Selectbox.vue').default)

Can't display data from parent in child component

I'm new to Vue.js and trying to build a small application that a user can select a number and view it in another page. The data passed from the parent component was not displayed in the child component like "You select: (a number)", it showed "You select:", without the number passed from the parent. Where did I do wrong? I really can't figure it out.
ParentComponent.vue
<template>
<div>
<p>Select a number:
<select v-model="num">
<option disabled value="">Select</option>
<option v-for="n in 10">{{n}}</option>
<child-component v-bind:select="num"></child-component>
</select>
</p>
</div>
</template>
<script>
import ChildComponent from '../components/ChildComponent'
export default {
name: 'ParentComponent',
components: {
"child-component": ChildComponent
},
data () {
return {
num: 0,
}
}
}
</script>
<style scoped>
</style>
ChildComponent.vue
<template>
<div>
<h2>{{msg}}</h2>
<p>You select: {{select}}</p>
</div>
</template>
<script>
export default {
name: 'ChildComponent',
props: {
select: Number
},
data () {
return {
msg: 'ChildComponent'
}
}
}
</script>
<style scoped>
</style>
You can't use <child-component> in the <select></select> tags, please pull out it from the select tag and run it.
<template>
<div>
<p>Select a number:
<select v-model="num">
<option disabled value="">Select</option>
<option v-for="n in 10">{{n}}</option>
</select>
<child-component v-bind:select="num"></child-component> /// run it in here//
</p>
</div>
</template>
<script>
import ChildComponent from '../components/ChildComponent'
export default {
name: 'ParentComponent',
components: {
"child-component": ChildComponent
},
data () {
return {
num: 0,
}
}
}
</script>
<style scoped>
</style>

Vue.js - component that binds a binary string to checkbox inputs

In Vue.js, how would I write a component that binds to a string of 1s and 0s, such as "111001011", and represents this data to the user as a set of named checkboxes?
Maybe this is what you'r looking for:
App.vue
<template>
<div id="app">
<checkboxes :binary="binary"></checkboxes>
</div>
</template>
<script>
import Checkboxes from './components/Checkboxes'
export default {
name: 'app',
data(){
return {
binary: "11001011"
};
},
components: {
Checkboxes
}
}
</script>
Checkboxes.vue:
<template>
<div>
<ul>
<li v-for="position in binary.length">
<label>
<input type="checkbox" :name="binary[position - 1]" :checked="binary[position - 1] == '1' ? true : false"> {{ binary[position - 1] }}
</label>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'checkboxes',
props: {
binary: {
required: true,
type: String
}
}
}
</script>
This will go through the string length and for each character will mark as checked/unchecked based on the binary value(1/0)
Result: