vuejs nested slots with props don't get down - vuejs2

I want to push down a prop "multi" from vDropdownSelection to "vOptions". How can I do that without adding ":multi" on each option? I tried slotprops but it doesn't work...
This is my setup.
<!-- root -->
<vDropdownSelection :multi="true">
<vOption id="dd5" label="Choose me" />
<vOption id="dd6" label="No take me" />
<vOption id="dd7" label="I don't care..."/>
</vDropdownSelection>
multi gets true
//vDropdownSelection
<template>
<vPopOver>
<template #trigger="{ click }">
<button #click.prevent="click">{{ label }}</button>
</template >
<template #default>
<vSelectGroup :multi="multi" #default="{multi}">
{{ multi }} // shows true
<slot :multi="multi"/> // cannot pass multi ยด
</vSelectGroup>
</template>
</vPopOver>
</template>
<script>
export default {
props: {
multi: {
type: Boolean,
default: false
}
}
}
</script>
multi gets true
//vSelectGroup
<template>
<div>
<slot :multi="multi"/>
</div>
</template>
<script>
export default {
props: {
multi: {
type: Boolean,
default: false
}
}
}
</script>
multi stays false...
// options
<template>
<div>
<input :type="isType">
<label>{{ label }}</label>
</div>
</template>
<script>
export default {
props: {
multi: {
type: Boolean,
default: false
}
},
computed: {
isType() {
return this.multi ? 'checkbox' : 'radio'
}
}
}
</script>

Related

function not updating vue property

I have this component:
<template>
<div class="hello">
<div>
My prop: {{ myprop }}?
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'StartPage',
props: {
myprop: {
type: String
}
},
model: {
prop: 'myprop',
event: 'click'
},
methods: {
changeText () {
this.$emit('click', 'sometext')
console.log('this.myprop', this.myprop)
}
}
})
</script>
Im using vue v3. Everytime I click on the button, I still see the text "My prop: ?" in the browser.
And in the console I can see: "this.myprop undefined" every time I click on the button.
What am I doing wrong?
As per my understanding, You are trying to update the prop text on click of button from the child component. If Yes, you can achieve it simply by emitting a new text and updating that in the parent component.
Live Demo :
const ShowPropText = {
template: `<div class="hello">
<div>
My prop: {{ myprop }}
</div>
<div>
<button class="fas fa-lock-open lock" #click="changeText()">Click</button>
</div>
</div>`,
props: ['myprop'],
methods: {
changeText() {
this.$emit('click-event', 'sometext')
}
}
}
const app = Vue.createApp({
components: {
'show-prop-text': ShowPropText
},
data() {
return {
text: 'This is default text'
}
},
methods: {
methodCall(e) {
this.text = e;
}
}
})
app.mount('#app')
<script src="https://cdn.jsdelivr.net/npm/vue#next"></script>
<div id="app">
<show-prop-text :myprop="text" #click-event="methodCall"></show-prop-text>
</div>

The Value of Variables does not update inside components

When I put the input field inside a component, it doesn't update the value by any means. Is there something I've missed? Btw, I use Vue 3.
Child Component (input-form.vue)
<template>
<input
type="text"
:value="searchField"
#input="$emit('update:searchField', $event.target.value)"
/>
<p>Text Inside: {{ searchField }}</p>
</template>
<script>
export default {
emits: ["update:searchField"],
props: {
searchField: {
type: String,
},
},
};
</script>
Parent
<template>
<div>
<input-form :searchField="searchField" />
<p>Text Outside: {{ searchField }}</p>
</div>
</template>
<script>
import inputForm from "components/input-form.vue";
export default {
data() {
return {
searchField: "",
};
},
components: {
inputForm,
},
};
</script>
You are not listening for the update:searchField event in the Parent.
<input-form :searchField="searchField" #update:searchField="searchField = $event" />
or
<input-form v-model:searchField="searchField" />

vuejs2 slots how to communicate with parent

I want to create a formRow component that have a slot for the input field and vee-validate for validation
this is my markup
//form
<vFormRow validate="required" v-slot="{ onInput, errors }">
<vTextfield #input="onInput" :errors="errors"/>
</vFormRow>
I tried to emit the value to the parent and get the value with #input="onInput" on the slot, but this doesn't work
//formrow
<template>
<div class="mb-4">
<v-validation-provider
v-slot="{ errors }"
:rules="validate"
>
<label>{{ label }}</label>
<slot
:onInput="onInput"
:errors="errors"
/>
<vFormError
:message="errors[0]"
/>
</v-validation-provider>
</div>
</template>
<script>
import { ValidationProvider as vValidationProvider } from 'vee-validate'
import vRadioButton from '#primitives/textfield'
import vFormError from '#primitives/formError'
export default {
components: {
vTextfield,
vFormError,
vValidationProvider
},
props: {
value: {
type: String,
default: '',
},
validate: {
type: String,
required: true,
}
},
methods: {
onInput(value) {
console.log(value)
}
}
}
</script>
//textfield
<template>
<div>
<input :value="value" #input="onInput"/>
</div>
</template>
<script>
export default {
props: {
value: {
type: String,
default: '',
},
errors: {
type: Array,
default: () => {}
}
},
data: {
return {
// local_value: ''
}
}
methods: {
onInput(e) {
// this.local_value = e.target.value
this.$emit('input', e.target.value)
}
}
}
</script>
What I'm doing wrong?
You're not actually passing the slot props to <vTextfield>. I think you might be assuming that data bindings and event handlers on the <slot> are automatically applied to the slot's children, but that's not true.
To use the value slot prop, destructure it from v-slot, and bind it to the <vTextfield> child:
<vFormRow validate="required" v-slot="{ value }">
<vTextfield :value="value" />
</vFormRow>
You could also pass the onInput method as a slot prop:
// vFormRow.vue
<slot :onInput="onInput" />
Then bind the event handler to <vTextfield>:
<vFormRow validate="required" v-slot="{ onInput }">
<vTextfield #input="onInput" />
</vFormRow>

Why is component shown just for a fraction of a second?

As a beginner in Vue, I am struggling with a problem that - even this should not be too hard - I can't solve. The principle is as follows:
I want to create a survey that consists of different topics. The user should be able to choose between these topics (component A and component B). This works fine.
But: When I click on the button "Show Component C", this component is only displayed for a fraction of a second. Why is this, what mistake have I made and how can I solve the problem?
Thanks a lot for your help!
App.vue
<button #click="setSelectedComponent('ComponentA')">Component A</button>
<button #click="setSelectedComponent('ComponentB')">Component B</button>
<component-b
v-if="selectedComponent === 'ComponentB'"
> </component-b>
<component-a
v-if="selectedComponent === 'ComponentA'"
></component-a>
<start
v-if="selectedComponent === 'form-empty'"
></start>
</template>
<script>
import ComponentB from './components/ComponentB.vue';
import ComponentA from './components/ComponentA.vue';
import Start from './components/Start.vue';
export default {
components: {
ComponentB,
ComponentA,
Start,
},
data() {
return {
selectedComponent: 'form-empty',
}
},
methods: {
setSelectedComponent(cmp) {
this.selectedComponent = cmp;
},
}
}
</script>
Start.vue
<template>
<form>
<div>
<h1>Which Component Do You Want To Select?</h1>
</div>
</form>
</template>
**
Component A
<template>
<form>
<h1>Component A</h1>
<div class="form-control">
<input type="range" min ="0" max="100" v-model=value>
</div>
<div>
<button #click="evaluateForm">Save Data</button>
</div>
<h4>Value: {{value}}</h4>
</form>
<component-c v-if="varia === 'yes'"></component-c>
</template>
<script>
import ComponentC from './ComponentC.vue';
export default {
components: {
ComponentC
},
methods: {
evaluateForm() {
this.varia='yes'
}
},
computed: {
result() {
return parseInt(this.abc) + parseInt(this.cde)
}
},
data() {
return {
value: '',
varia: ''
}
}
}
</script>
Component B
<template>
<form>
<h1>Component B</h1>
<div>
<input type="range" min ="0" max="100" v-model=value>
</div>
<div>
<button #click="evaluateForm">Save Data</button>
</div>
<h4>Value: {{value}}</h4>
</form>
<component-c v-if="varia === 'yes'"></component-c>
</template>
<script>
import ComponentC from './ComponentC.vue';
export default {
components: {
ComponentC
},
methods: {
evaluateForm() {
this.varia='yes'
}
},
computed: {
result() {
return parseInt(this.abc) + parseInt(this.cde)
}
},
data() {
return {
value: '',
varia: ''
}
}
}
</script>
Component C
<template>
<form>
<div class="form-control">
<h1>The value is: </h1>
</div>
</form>
</template>
I tested this out locally and the problem comes from the fact that you are using <form> in ComponentA and ComponentB. If you switch those to <div> or <form #submit.prevent> you'll see that it works as you expected.
Here is some documentation on the <form> element to learn more about how it works: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form
Component A
<template>
<div>
<h1>Component A</h1>
<div>
<input type="range" min ="0" max="100" v-model=value>
</div>
<div>
<button #click="evaluateForm">Save Data</button>
</div>
<h4>Value: {{value}}</h4>
</div>
</template>
<script>
export default {
methods: {
evaluateForm() {
this.$emit('xxx');
}
},
computed: {
result() {
return parseInt(this.abc) + parseInt(this.cde)
}
},
data() {
return {
value: '',
}
}
}
</script>
App.Vue
<template>
<button #click="setSelectedComponent('ComponentA')">Component A</button>
<button #click="setSelectedComponent('ComponentB')">Component B</button>
<component
:is="selectedComponent"
></component>
<component-a
#xxx="startComponentC"
v-if="varia === 'yes'"
></component-a>
<component-c
v-if="varia === 'yes'"
></component-c>
</template>
<script>
import ComponentB from "./components/ComponentB.vue";
import ComponentA from "./components/ComponentA.vue";
import Start from "./components/Start.vue";
export default {
components: {
ComponentB,
ComponentA,
Start,
},
data() {
return {
selectedComponent: "start",
varia:""
};
},
methods: {
setSelectedComponent(cmp) {
this.selectedComponent = cmp;
},
startComponentC() {
this.varia="yes"
this.selectedComponent="stopConditionforComponentAandB"
}
},
};
</script>

How to get data from a component in VueJS

I have the following component:
Component
<template>
<div>
<label class="typo__label">Single selecter</label>
<multiselect v-model="value" :options="options" :searchable="false" :close-on-select="false" :show-labels="false" placeholder="Pick a value"></multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
data () {
return {
value: '',
options: ['Select option', 'options', 'selected', 'mulitple', 'label', 'searchable', 'clearOnSelect', 'hideSelected', 'maxHeight', 'allowEmpty', 'showLabels', 'onChange', 'touched']
}
}
}
</script>
I am using it in my page like so:
<p id="app-two">
<dropdown></dropdown>
#{{ value }}
#{{ message }}
</p>
<script>
new Vue({
el: '#app',
data: {
message: 'Test message'
}
});
</script>
When I run the page, #{{ message }} shows "test message" but #{{ value }} is blank.
I can see the value of the dropdown component getting updated in VueJS Dev Tools but it does not show on the page. How do I access the components data in my vue element? Something like #{{ dropdown.value }}
<template>
<div>
<label class="typo__label">Single selecter</label>
<multiselect v-model="internalValue" :options="options" :searchable="false" :close-on-select="false" :show-labels="false" placeholder="Pick a value"> </multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
export default {
components: {
Multiselect
},
props: ['value'],
data () {
return {
internalValue: this.value,
options: ['Select option', 'options', 'selected', 'mulitple', 'label', 'searchable', 'clearOnSelect', 'hideSelected', 'maxHeight', 'allowEmpty', 'showLabels', 'onChange', 'touched']
}
},
watch:{
internalValue(v){
this.$emit('input', v);
}
}
}
</script>
and in your page
<p id="app-two">
<dropdown v-model="selectedValue"></dropdown>
#{{ selectedValue}}
#{{ message }}
</p>
<script>
new Vue({
el: '#app',
data: {
selectedValue: null
message: 'Test message'
}
});
</script>
Here is an example, not using multi-select, but a custom component that implements support for v-model.
This is the best and cleanest way for me.
Parent component
<template>
<ChildComponent v-model="selected" />
</template>
Child component
<template>
<Multiselect
:value="value"
:options="options"
:show-labels="false"
:multiple="true"
:close-on-select="false"
:clear-on-select="false"
:searchable="false"
:limit="1"
:limit-text="(count) => $t('app.multiselect.and_n_more', { n: count })"
:placeholder="$t('app.select')"
label="name"
track-by="name"
#input="$emit('input', $event)"
/>
</template>
<script>
export default {
props: {
value: {
type: Array,
default: () => []
}
},
data() {
return {
options: [{id:1, name:'John'}, {id:2, name:'Tom'}]
}
}
}
</script>