How to get data from a component in VueJS - vuejs2

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>

Related

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" />

VueJS props issue something missing

I have a tabbed view and I need to pass a value from a select field to the tabs but I don't get props right. This is the parent:
<template>
<div>
<b-form-group id="memberListing" label-for="memberListing" class="mr-sm-2">
<b-form-select
v-model="memberSelection"
:title="memberSelection"
#change="getUserID"
aria-describedby="memberListing"
>
<option disabled value="" selected>Mitglied auswählen</option>
<option
v-for="member in memberList"
v-bind:key="member"
:value="member.cb_userid"
lazy
>
{{member.user_name}}
</option>
</b-form-select>
</b-form-group>
<Biometrics :title="memberSelection"></Biometrics>
<b-card title="Card Title" no-body>
<b-card-header header-tag="nav">
<b-nav card-header tabs>
<b-nav-item to="/users/profile" exact exact-active-class="active"
>Profil</b-nav-item
>
<b-nav-item
to="/users/trainingsplans"
exact
exact-active-class="active"
>Trainingspläne</b-nav-item
>
<b-nav-item to="/users/biometrics" exact exact-active-class="active"
>Biometrie</b-nav-item
>
</b-nav>
</b-card-header>
<b-card-body>
<router-view></router-view>
</b-card-body>
</b-card>
</div>
</template>
<script>
import axios from 'axios'
import Biometrics from "#/components/users/biometrics.vue";
export default {
data: () => {
return {
profileList: 'http://localhost:8000/userProfiles/profileList',
memberList: [],
memberSelection: null,
}
},
props: {
},
components: {
Biometrics
},
async mounted() {
try {
let memberListData = await axios.get(this.profileList)
this.memberList = memberListData.data
console.log(this.memberList)
} catch (e) {
this.errors.push(e)
}
},
methods: {
getUserID: function () {
// this.childMemberSelect = this.memberSelection
// console.log(this.childMemberSelect)
},
},
}
</script>
What am I missing? I'm trying for hours now but I cant get the value to show up in the specified tab when I select the value.
this is the child :
<pre>
<template>
<div>
{{title}}
</div>
</template>
<script>
export default {
created () {
console.log(this.title)
},
methods: {},
props: {
title: Number,
},
data() {
return {
}
},
components:{},
}
</script>
</pre>

Form data should remain after displaying error

I am new to inertia js and creating a project using Laravel and inertia js, I am facing an issue that form data is erased after any error display. How to prevent that in inertia.
I have already tried preserveState.
Vue code:
<template>
<template #breadcrumb>
<div>
<div>
<button #click="submit">Save</button>
</div>
</div>
</template>
<div>
<div>
<label>Name</label>
<t-input type="text" v-model="form.name" />
<div v-if="errors['name']">{{ errors["name"] }}</div>
</div>
<div>
<label>Comment</label>
<t-input type="text" v-model="form.comment" />
<div v-if="errors['comment']">{{ errors["comment"] }}</div>
</div>
</div>
</template>
<script>
import { Inertia } from '#inertiajs/inertia'
export default {
components: {
Inertia
},
props: {
form: Object,
errors: Object,
},
methods: {
submit() {
Inertia.post(this.route("post.store"), this.form, { preserveState: true });
},
},
};
</script>
Controller code
public function store(Request $request)
{
$request->validate([
'name' => ['required', 'string'],
'comment' => ['required', 'string'],
]);
$data = [
'name' => $request->get('name'),
'comment' => $request->get('comment'),
];
Post::create($data);
return redirect(route('post'))->with('success', 'Post created.');
}
Try using the form helper (read up on it here https://inertiajs.com/forms) something like this in your Vue component binding on the form props, not the prop you pass into the vue:
<template>
<template #breadcrumb>
<div>
<div>
<button #click="submit">Save</button>
</div>
</div>
</template>
<div>
<div>
<label>Name</label>
<t-input type="text" v-model="myForm.name" />
<div v-if="myForm.error('name')">{{ myForm.error('name') }}</div>
</div>
<div>
<label>Comment</label>
<t-input type="text" v-model="myForm.comment" />
<div v-if="myForm.error('comment')">{{ myForm.error('comment') }}</div>
</div>
</div>
</template>
<script>
import { Inertia } from '#inertiajs/inertia'
export default {
components: {
Inertia
},
props: {
form: Object,
errors: Object,
},
data() {
return {
myForm: Inertia.form(
{
name: this.form.name,
comment: this.form.comment,
},
}
},
methods: {
submit() {
this.myForm.post(this.route("post.store"));
},
},
};
</script>

Vue: How do you bind a value to an input through a wrapper component?

I know you can use v-model to bind a value to an input in the same component. How do you create a wrapper component for an input and bind a value to it?
Login.vue
<template>
<div id="Login">
<Input v-bind:value="email"/>
<Input v-bind:value="password"/>
</div>
</template>
<script>
import Input from './Input.vue'
import Button from './Button'
export default {
name: 'Login',
components: {
Input,
Button,
},
data: () => ({
email:'test',
password:'test',
}),
methods: {
login: () => { debugger; }, //this.email and this.password are still set to test
}
}
</script>
Input.vue
<template>
<div class="input>
<input v-model="value"/>
</div>
</template>
<script>
export default {
name: 'Input',
props: {
value: String,
},
}
</script>
Current set up results in
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"
Is the only way to do this by emitting an event?
If I got it correctly, you can try to create transparent wrapper (in my case AppInput)
SomeParent.vue
<div>
<AppInput v-model="parentModel" />
</div>
AppInput.vue
<template>
<input
class="app-input"
v-bind="$attrs"
:value="value"
v-on="{
...$listeners,
input: event => $emit('input', event.target.value)
}">
</template>
<script>
export default {
name: "AppInput",
inheritAttrs: false,
props: ["value"]
};
</script>
one of articles
The best way is use v-model for wrapper and on/emit for input
<div id="Login">
<Input v-model="email"/>
<Input v-model="password"/>
</div>
...
<div class="input>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</div>
You can implement v-model directly in the input component by doing so.
<template>
<div class="input>
<input :value="value" #input="$emit('input', $event.target.value)"/>
</div>
</template>
<script>
export default {
name: 'Input',
props: ["value"]
}
</script>
And then use it in your parent component like this:
<template>
<div id="Login">
<Input v-model="email"/>
<Input v-model="password"/>
</div>
</template>
<script>
import Input from './Input.vue'
import Button from './Button'
export default {
name: 'Login',
components: {
Input,
Button,
},
data: () => ({
email:'test',
password:'test',
}),
methods: {
login: () => { debugger; }, //this.email and this.password are still set to test
}
}
</script>
See here

VueJS + VueRouter + Bootstrap-vue (modal from modal) = <failed to convert exception to string>

I'll try display modal from modal (I'll create separate components for each modal). When second modal is closed I want to return to first modal. But after I'm display first modal second time I got error 'failed to convert exception to string' from administration.js. I'm using VueRouter too.
administration.js (main entry with router-view) -> partner.vue (with partnerEditor.vue component)
partnerEditor.vue
<template>
<div>
<b-modal ref="partnerEditor" title="Partner" :busy="isBusy" cancel-title="cancel" ok-variant="info" ok-title="save" v-on:ok="onCreate">
<div class="form-group">
<div class="input-group mb-3">
<select class="form-control">
<option v-for="contact in contacts">{{ contact.name }}</option>
</select>
<div class="input-group-append">
<b-btn v-on:click="$refs.contactEditor.show()"></b-btn>
</div>
</div>
</div>
</b-modal>
<contactEditor ref="contactEditor" v-on:hide="$refs.partnerEditor.show()"></contactEditor>
</div>
</template>
<script>
export default {
data() {
return {
contacts: [],
isBusy: false
}
},
methods: {
show() {
this.$refs.partnerEditor.show();
}
},
components: {
contactEditor: () => import('./contactEditor.vue'),
},
}
</script>
contactEditor.vue
<template>
<b-modal ref="contactEditor" title="Contact" :busy="isBusy" cancel-title="cancel" ok-variant="info" ok-title="save" v-on:ok="onCreate" v-on:hide="$emit('hide')">
<div class="form-group">
<label>name</label>
<input type="text" class="form-control" placeholder="" />
</div>
</b-modal>
</template>
<style></style>
<script>
export default {
model: {
event: 'hide'
},
data() {
return {
isBusy: false
}
},
methods: {
show() {
this.$refs.contactEditor.show();
},
}
}
</script>
routes
const router = new VueRouter({
routes: [
{
name: 'configuration', path: '/configuration', component: () => import('./administrator/configuration/index.vue'),
children: [
{ name: 'configuration-partner', path: '/configuration/partner', component: () => import('./administrator/configuration/partner.vue') }
]
}
]
});