Vue js v-if condicional rendering on a shared toggle button - javascript

//PARENT COMPONENT
<template>
....
<div class="input-wrapper">//Toggle button container
<label class="input-label">
SELECT YES OR NOT
</label>
<toggle //child component, toggle button
:options="shipping"
/>
</div>
<div
v-if="destiny[0].value"
class="input-wrapper">
<label class="input-label">
IF YES THIS CONTAINER WILL BE DISPLAYED
</label>
<toggle
:options="Options"
/>
</div>
.....
</template>
<script>
import Toggle from "....";
export default {
components: {
Toggle,
},
data: function () {
return {
destiny: [{
label: 'Yes',
value: true
},
{
label: 'No',
value: false
}
],
Options: [{
label: 'A',
value: 'a'
},
{
label: 'B',
value: 'b'
},
{
label: 'C',
value: 'c'
}]
}
}
}
</script>
///CHILD COMPONENT
<template>
<div class="toggle">
<button
v-for="option in options"
:key="option.value"
:class="{
active: option.value === value
}"
class="btn"
#click="() => toggleHandler(option.value)">{{ option.label }} .
</button>
</div>
</template>
<script>
export default {
props: {
options: {
type: Array,
required: true
}
},
data: function () {
return {
value: this.options[0].value
}
},
methods: {
toggleHandler (value) {
this.$emit('input', value)
this.value = value
}
}
}
</script>
There is toggle with to options YES or NOT, if yes is selected the child component will be rendered otherwise will keep hide.
I'm trying to use a conditional in order to display a child component into a parent component using directives v-if or v-show, but I could not find the way to send the boolean value from the child component to the parent component.

Hope this helps!!
// CHILD
Vue.component('child', {
template: '<div>TOGGLE:- <input type="checkbox" #click="emit"/></div>',
data() {
return {
checked: false
};
},
methods: {
emit: function() {
this.checked = !this.checked;
this.$emit('event_child', this.checked);
}
}
});
// PARENT
var vm = new Vue({
el: '#app',
data: function() {
return {
toggleStatus: false
}
},
methods: {
eventChild: function(checked) {
this.toggleStatus = checked;
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="app">
<child v-on:event_child="eventChild"></child>
<div id="toggle">TOGGLE STATUS => {{toggleStatus}}</div>
</div>

Related

Emit in vue does not upgrade property in parent component

The emit works, I can see that in the vue developer tool. But the property in the parent element does not upgrade.
Child Component:
<template>
<div>
<ul>
<li v-for="(option, index) in options" :key="index" #click="selectOption(index)">
{{ option }}
</li>
</ul>
</div>
</template>
<script>
export default {
name: "Dropdown",
props: {
options: {
type: Array,
},
},
data() {
return {
value: "",
}
},
methods: {
selectOption(id) {
this.value = this.options[id];
this.$emit("clickedOption", this.value);
}
}
}
</script>
Parent Component:
<button v-on:clickedOption="selectRole($event)">Select Role</button>
methods: {
selectRole(value) {
this.role = value.payload;
},
It seems that the function selectRole is not getting executed.
I had to give the parent element the emit function like this:
<Dropdown :options="roleOptions" v-show="dropdownToggle" #clickedOption="selectRole($event)"></Dropdown>

Vue.js : Method not firing in parent component after emit

A child component emits an event on input change with a payload:
Vue.component('gum-option', {
inheritAttrs: false,
props: ['label'],
template: `
<label class="gum-option">
<input
type="radio"
v-bind="$attrs"
v-on:change="$emit('update', this.label)">
<span>{{ label }}</span>
</label>
`
});
Its parent component listens to this event in order to fire a method that throws an alert:
Vue.component('gum-select', {
template: `
<div v-on:update="updateValue">
<label>{{label}}</label>
<div class="selected">
{{selectedOption}}
</div>
<slot v-bind="options"></slot>
</div>
`,
data: function () {
return {
selectedOption: ''
}
},
props:['options', 'name', 'label'],
methods: {
updateValue: function(event) { // method invoked by the "update" event
alert(event); // Not firing ! Why
}
}
});
You can find the bug on this pen:
https://codepen.io/bourpie/pen/JjXdjzg?editors=1011
The listener should be put on the gum-option component in App, as well as the method updateValue. There were some other mistakes so this is the fixed demo:
<div id="myApp">
<gum-select name="options" label="Options" v-bind:options="options" >
<gum-option
v-for="option in options"
v-bind:key="option.value"
v-bind:value="option.value"
v-bind:label="option.texte"
name="province"
v-on:update="updateValue">
</gum-option>
</gum-select>
</div>
Vue.component('gum-option', {
inheritAttrs: false,
props: ['label'],
template: `
<label class="gum-option">
<input
type="radio"
v-bind="$attrs"
v-on:change="$emit('update', label)">
<span>{{ label }}</span>
</label>
`
});
Vue.component('gum-select', {
template: `
<div>
<label>{{label}}</label>
<div class="selected">
{{selectedOption}}
</div>
<slot v-bind="options"></slot>
</div>
`,
data: function () {
return {
selectedOption: ''
}
},
props:['options', 'name', 'label'],
});
new Vue({
el: '#myApp',
data: {
options: [
{value: '1', texte: 'Option 1'},
{value: '2', texte: 'Option 2'},
{value: '3', texte: 'Option 3'}
]
},
methods: {
updateValue: function(label) {
console.log(label);
}
}
});

how to pass default value in multiselect component to another vue-multiselect

I want to pass the default value of vue multiselect component use props, but I can't do this.
I use two selectors. When one option in select-1 selects I want the default value in select-2 is option select
No error just doesn't work properly. The value selected from the first selection does not fall into the default value of the second selection
multiselect component
<template>
<div>
<multiselect v-model="internalValue" id="currency_id" #input="onchange" placeholder="Select Your Currency" label="title" track-by="title" :options="options" :option-height="10" :show-labels="false">
<template slot="singleLabel" slot-scope="props"><img class="option__image" :src="props.option.img"><span class="option__desc"><span class="option__title">{{ props.option.title }}</span></span>
</template>
<template slot="option" slot-scope="props"><img class="option__image" :src="props.option.img">
<div class="option__desc"><span class="option__title" :id="props.option.id">{{
props.option.title }}</span><span class="option__small">{{ props.option.desc }}</span></div>
</template>
</multiselect>
</div>
</template>
import Vue from 'vue';
import Multiselect from 'vue-multiselect'
Vue.component('multiselect', Multiselect);
export default {
props: ['options', 'value'],
components: {
Multiselect
},
data() {
return {
internalValue: this.value,
}
},
methods: {
onchange(options) {
this.$emit('selectvalue', options.id);
}
},
watch: {
internalValue(v) {
this.$emit('input', v);
}
}
}
HTML
**select 1**
<multiselect #selectvalue="apiCalc":options="[
{
id: '1', title: 'Tether', img: 'https://coinnik.com/uploads/crypto-logos/006fe133d48ea7cd45cf8ccb8cb7ec42.png'
}
,
{
id: '2', title: 'ether', img: 'https://coinnik.com/uploads/crypto-logos/006fe133d48ea7cd45cf8ccb8cb7ec42.png'
}
,
{
id: '3', title: 'bitcoin', img: 'https://coinnik.com/uploads/crypto-logos/006fe133d48ea7cd45cf8ccb8cb7ec42.png'
}
]"
> </multiselect>
select2
<multiselect id="receive-currency" :options="receive_currency" v- model="selectedValue"></multiselect>
app.js
new Vue({
el: "#calculate",
data: {
receive_currency: [],
selectedValue: null,
},
methods: {
apiCalc(options) {
let self = this;
this.sendCurrencyId = options;
var receiveCurrency = [];
for (let item in responseData.data.direction.data) {
receiveCurrency.push({
title: responseData.data.direction.data[item].receiveCurrency.data.title,
img: '',
});
}
self.receive_currency = receiveCurrency;
self.selectedValue = receiveCurrency[0]
})
}
}
},
components: {
'multiselect': Multiselect
},
created() {
this.apiCalc();
},
});
In template:
<multiselect v-model="multiSelect1" :options="options" #input="onChange"></multiselect>
<multiselect v-model="multiSelect2" :options="options" :placeholder="placeholder"></multiselect>
In script:
data: () => ({
multiSelect1: "",
multiSelect2: "",
options: ["list", "of", "options"],
placeholder: "Select option"
}),
methods: {
onChange() {
this.multiSelect2 = this.multiSelect1
}
}
Please check this codesandbox: https://codesandbox.io/s/vue-template-t226h

Vue JS - injecting default value to custom radio group

So i tried to inject a default value to custom radio component that i wrote
Here's the code:
<template>
<div class="custom-radio-button">
{{value}}
<div v-for= "item in localValue">
<input type="radio" :value="item.value" name=item.name #click=onSelected(item.value) >
<span>{{item.label}}</span>
</input>
</div>
</div>
<script>
import Vue from 'vue'
const name = 'CustomRadioButton'
export default {
name,
componentName: name,
props: [ 'name', 'value', 'isDefault', 'label'],
data() {
return {
localName: this.name,
localValue: this.value
}
},
methods: {
onSelected (value) {
this.$emit('clicked', value)
}
}
}
</script>
And here's how i called it:
<CustomRadioButton :value=RadioFieldData #clicked="isRadioButtonSelection" isDefault='yellow'></CustomRadioButton>
And here's the Json Data that goes with it
RadioFieldData:[
{label:'Fire', value:'red', name:'colour' },
{label:'Sun', value:'yellow', name:'colour',isDefault:'yellow'},
{label:'Water', value:'blue', name:'colour'}
]
My question is what is the best way to pass the value "yellow" to the radio buttons group?
Your issue is that props need to be represented in their kebab-case format when used in your template. To set isDefault to "yellow", you need to use
is-default="yellow"
See https://v2.vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case
Once you're able to read that property correctly, you can use
:checked="item.value == isDefault"
Here's an example.
Vue.component('custom-radio-button', {
template: `<div class="custom-radio-button">
Default: {{isDefault}}
<div v-for="item in value">
<input type="radio" :value="item.value" name="item.name" #click="onSelected(item.value)" :checked="item.value == isDefault" />
<span>{{item.label}}</span>
</div></div>`,
props: ['value', 'isDefault'],
methods: {
onSelected(value) {
this.$emit('clicked', value)
}
}
})
new Vue({
el: '#app',
methods: {
isRadioButtonSelection (val) {
console.log('isRadioButtonSelection', val)
}
},
data: {
RadioFieldData: [{"label":"Fire","value":"red","name":"colour"},{"label":"Sun","value":"yellow","name":"colour","isDefault":"yellow"},{"label":"Water","value":"blue","name":"colour"}]
}
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<custom-radio-button :value="RadioFieldData"
#clicked="isRadioButtonSelection"
is-default="yellow">
</custom-radio-button>
</div>

What's the best way to pass and retrieve data from a child form component?

This is my current method:
Parent.vue:
// Template
<form-child :schema="schema"><form-child>
// JS
data () {
return {
schema: [{ // name: '', value: '', type: '' }, { //etc ... }]
}
}
FormChild.vue:
// Template
<div v-for="field in schema">
<input v-if="field.type === 'text'" #change="updateValue(field.name, field.value)">
<textarea v-if="field.type === 'textarea'" #change="updateValue(field.name, field.value)">/textarea>
</div>
// JS
props: {
schema: Arrary
}
methods: {
updateValue (fieldName, fieldValue) {
this.schema.forEach(field => {
// this makes schema update in Parent.vue
if (field.name === fieldName) field.value = fieldValue
})
}
}
Is this the optimal way? Or maybe there's a better one using emit and v-model? (If so, could you provide a sample code?)
A properly encapsulated child component would be decoupled from the parent data structure. It would take type and value as separate props, plus an opaque id to tell the parent which value the component is emitting about.
By making a settable computed based on the value parameter, the component can use v-model on its form elements. The set function emits an input event with the id and the newValue, and the parent takes it from there.
Update: I decided I didn't like the id going to the component, so I handled that in the input handler: #input="updateField(index, $event).
new Vue({
el: '#app',
data: {
schema: [{
type: 'text',
name: 'one',
value: "1"
},
{
type: 'textarea',
name: 'two',
value: "stuff in the textarea"
}
]
},
methods: {
updateField(index, newValue) {
this.schema[index].value = newValue;
}
},
components: {
formInput: {
props: ['type', 'value'],
computed: {
proxyValue: {
get() { return this.value; },
set(newValue) {
this.$emit('input', newValue);
}
}
}
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<div v-for="field in schema">
{{field.name}} = {{field.value}}
</div>
<form-input inline-template v-for="field, index in schema" :type="field.type" :key="index" :value="field.value" #input="updateField(index, $event)">
<div>
<input v-if="type === 'text'" v-model="proxyValue">
<textarea v-if="type === 'textarea'" v-model="proxyValue"></textarea>
</div>
</form-input>
</div>
For what you are doing here, there is no need to separate the form into a component. Just make it part of the parent and use v-model.
new Vue({
el: '#app',
data: {
schema: [{
type: 'text',
name: 'one',
value: "1"
},
{
type: 'textarea',
name: 'two',
value: "stuff in the textarea"
}
]
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<div v-for="field in schema">
{{field.name}} = {{field.value}}
</div>
<div v-for="field in schema">
<input v-if="field.type === 'text'" v-model="field.value">
<textarea v-if="field.type === 'textarea'" v-model="field.value"></textarea>
</div>
</div>
If you want the component for reusability and you don't care about insulating the parent from changes (best practice is not to have anything outside a component change its data), you can just wrap the same thing in a component:
new Vue({
el: '#app',
data: {
schema: [{
type: 'text',
name: 'one',
value: "1"
},
{
type: 'textarea',
name: 'two',
value: "stuff in the textarea"
}
]
},
components: {
formChild: {
props: ['value']
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.min.js"></script>
<div id="app">
<div v-for="field in schema">
{{field.name}} = {{field.value}}
</div>
<form-child inline-template v-model="schema">
<div>
<div v-for="field in value">
<input v-if="field.type === 'text'" v-model="field.value">
<textarea v-if="field.type === 'textarea'" v-model="field.value"></textarea>
</div>
</div>
</form-child>
</div>

Categories

Resources