passing prop to child component not updating the dom - vuejs2

I have following situation:
i have a form (child)component that has a input field.
//child component
<input type="text" placeholder="Field" v-model="rs.title"/>
and rs here is a prop passed down by parent component
I have a parent component in which i create many instance of this component like:
<form v-for="(row,index) in no_of_segments" :rs.sync="row"/>
i am doing this way because i also need to track field values of all form components.
so i have a array no_of_segments defined in parent component which contains values like this :
[{'field':val1},{'field':val2},...]
I pass objects in this array down to child component as prop so that each field can be rendered with its values:
But the problem is when i push a new item to no_of_segments in parent component, a new instance of form get created but without its values being rendered.

Related

Vue 2. How get child value throuth v-model binding

I'm using v-model in custom component, but when I try to get the data(value props) of the child component in the parent component, then I get the old value, although the data in the parent has changed. If I get the data of the child component through setTimeout, then I get the data I need. How do I synchronize the v-model #input event and the data I receive from the child element in the parent?
This is the logic: there are AppForm(parent) component and AppSelect(child) component. I'm binding v-model on AddSelect, and I follow the changes through watch() { v-model-data }. Then v-model data has changed I call AppForm.data() method, which iterates through the list of children and gets the value prop of AppSelect component, but this value is old.
Short example:
https://codesandbox.io/s/serene-wildflower-5seqx?file=/src/App.vue
You're trying to get the child component's prop inside a watcher watching the data property that the prop is bounded to. Of course, the watcher triggers first, then the data is passed onto the child component and the prop is updated. Its not a good design if you are relying on the order that Vue events and functions are fired, but if you must, you can use vm.$nextTick() function to get values after everything is synced.
watch: {
selectData(newV, oldV) {
alert("Select data from parent component: " + newV);
this.$refs.form.data();
this.$nextTick(() => {
alert("Show select data after 2sec");
this.$refs.form.data();
}, 2000);
},
},
Although, I'd suggest you shift the watcher inside the child component and access the data prop there.

VueJs - What's The Correct Way to Create a Child Component With Input Fields

I'm trying to use vuejs to display a list of instances of a child component.
The child component has input fields that a user will fill in.
The parent will retrieve the array of data to fill in the child components (If any exists), but since they're input fields the child component will be making changes to the value (Which generates errors in the console, as child components aren't supposed to change values passed from the parent).
I could just be lazy and just do everything at the parent level (i.e. use a v-for over the retrieved array and construct the list of elements and inputs directly in the parent and not use a child component at all), but I understand that it's not really the vuejs way.
I'm not very familiar with child components, but I think if it was just static data I could just declare props in the child component, and fill it from the parent.
However what I kind to need to do is fill the child component from the parent, but also allow changes from within the child component.
Could someone please describe the correct way to achieve this?
Thanks
You can use inputs on child components. The pattern is like this (edit it's the same pattern for an array of strings or an array of objects that each have a string property as shown here):
data: function() {
return {
objects: [ { someString: '' }, { someString: '' } ]
}
}
<the-child-component v-for="(object, i) in objects" :key="i"
v-model="object.someString"
></the-child-component>
Then, in the child component:
<template>
<div>
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
/>
</div>
</template>
export default {
name: 'the-child-component',
props: ['value'],
}
See it described here: https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Notify parent component as soon as event occurs in child event?

I need that when a user clicks a button on the child component the parent component receives cart.lenght to be assigned the count property of an element.
Child component code
<q-btn flat round color="faded" icon="fas fa-shopping-cart" #click="cart(item.id)"/>
cart: function (Id) {
let cart = []
cart.push(Id)
this.$emit('totalItensCart')
this.$q.localStorage.set('cart', cart)
}
How do I display the cart.length value in the count property that is in the parent component?
Parent component code
<q-route-tab
count="5"
icon="fas fa-cart-plus"
to="/cart"
exact
slot="title"/>
As per the vue event documentation, we want to emit an event from the child component to the parent component. You are correct with the this.$emit method, but it can take two parameters in order to pass data, like so:
this.$emit("name", data);
So, let's emit a count of the number of items in the cart from the first child:
this.$emit("cartUpdate", cart.length);
Now we need to handle this in the parent. We'll first need a data property to keep track of the totalCartItems in the parent:
data: function () {
return {
totalCartItems: null
}
}
Assuming that both of your code snippets are in different children of the same parent, and that the first child (the one that emits cartUpdate) has the component name first-child:
<first-child #cartUpdate="cartUpdate"></first-child>
This will call the cartUpdate() method in the parent component whenever the child emits an event called cartUpdate (using the # shorthand for v-on). The method is very simple, only updating the totalCartItems data property in the parent:
cartUpdate: function (totalCartItems) {
this.totalCartItems = totalCartItems;
}
Finally, let's ensure this gets updated in the second child component by binding it to the data value:
<q-route-tab
:count="totalCartItems"
icon="fas fa-cart-plus"
to="/cart"
exact
slot="title"/>

How to send communication to parent component from child component?

I have split up the components only for the reason the base or the parent component code is growing in size and for code organization. so split the components based on the sections of the parent component.
So the each child component are the each section of the same parent component. But my question how to access the child component objects from parent component? Because most of the examples i see are based on the click event from parent component to view the child component (like dialog) and the value is passed back to the parent html click event and captures the values using emitter and output parameter.
Whereas in my case there is no such click action to trigger the child component. So how to communicate the values from child component to parent component?
In parent component
onDocumentSelect( documentData: IDocument) {
console.log(documentData);
}
<app-document [showDocument] = 'displayDocument' (selectDocument)=onDocumentSelect($event)></app-document>
In Child component:
#Output() selectDocument: EventEmitter<e.IDocument>;
#Input() showDocument: boolean;
I am triggering emit in the function where the data for the DocumentSource is computed.
this.selectDocument.emit(this.DocumentSource.data);
here this.DocumentSource is the dataTable which has value in Child component, that needs to be accessed in parent component.
Apart from this I have similar data for another field of different type needs to be passed to parent component from child component.
I get the below error while page loads
TypeError: Cannot read property 'subscribe' of undefined
In the above code snippet, by changing the type to any solved the issue.
On child component:
#Output() public selectDocument: EventEmitter<any> = new EventEmitter<any>();
On parent component:
onDocumentSelect( documentData: any) {
console.log(documentData);
}

Delete a Vue child component

I'm really stuck on this one.I have created a Vue (2.0) component that is made up of child components, it's all being Webpacked etc. For example, this is the parent:
<div>
<h1>This is just a title for lulz</h1>
<rowcomponent v-for="row in rows" :row-data="row"></rowcomponent>
</div>
which has a prop of rows passed to it which looks something like this:
rows: [{ sometext: "Foo"} , { sometext: "Bar" }]
So my row component looks like this:
<div>{{ this.sometext }} <button #click="deleteRow">Delete Row</button></div>
And I feel like it should be really easy to set a method on the rowcomponent that is something like this:
deleteRow() {
this.delete();
}
Do I need to $emit something to the parent with the index of the row in it to remove it? It's driving me crazy. All the examples seem to suggest it would be easy to do, but not in the case where you have child components that want to delete themselves.
Yes, the child component cannot delete itself. The reason is because the original data for rows is held in the parent component.
If the child component is allowed to delete itself, then there will be a mismatch between rows data on parent and the DOM view that got rendered.
Here is a simple jsFiddle for reference: https://jsfiddle.net/mani04/4kyzkgLu/
As you can see, there is a parent component that holds the data array, and child component that sends events via $emit to delete itself. The parent listens for delete event using v-on as follows:
<row-component
v-for="(row, index) in rows"
:row-data="row"
v-on:delete-row="deleteThisRow(index)">
</row-component>
The index property provided by v-for can be used to call the deleteThisRow method, when the delete-row event is received from the child component.