Vue propsData not updating dynamically - javascript

I've been struggling with this issue for hours:
I've instantiated dynamically a child vue component inside a parent component, and passed in propsData some of the parent's data. The dynamically created child's properties doesn't seem to update when the parent updates.
Please check the example I created for a better understanding (forked from chinchang's example)
As you can see, I'm instantiating Button components both dynamically and statically. The color of the button depends on the type property. I pass the parent's data(the type attribute) as props both to the dynamically and statically created instances. When you insert a new button, by clicking the 'Click to insert' button, a new Button is created, using the parent's current type. After the click event, I switch the parent's type attribute. As you can see the statically created button instance (on the top on the page) changes color, but the dynamically instantiated ones remain the same.
Could you point out my mistake please and help to find a solution?
Thanks,
Ábel

From the docs:
Pass props to an instance during its creation. This is primarily
intended to make unit testing easier.
Setting propsData does not create a parent-child relationship. It simply provides (non-reactive) data to the component. In short, you've chosen a not-very-Vue approach. You shouldn't be concerned with creating components, you should have data items in your viewmodel that Vue then creates components for.
export default {
name: 'app',
components: { Button },
data(){
return {
type: 'secondary',
buttons: []
};
},
methods: {
onClick() {
this.buttons.push(true);
if(this.type === 'primary'){
this.type = 'secondary';
} else {
this.type = 'primary';
}
}
}
}
and
<div ref="container">
<button #click="onClick">Click to insert</button>
<Button v-for="b in buttons" :type="type">Click me!</Button>
</div>
Fixed demo

Related

Sending a prop using sync and binding it using v-model in child

I'm working with BootstrapVue to get this Accordian like component to work. Part of that entails setting the visibility of a particular item.
Ie,
const obj = {
someData: [...// properties here],
visible: false
}
And this gets fed down to an Accordian component like so:
<Accordian :visible.sync="obj.visible" />
And inside Accordian:
props: {
visible: {
type: Boolean
}
}
THEN... I need to attach it to a b-collapse html tag using v-model because that is how it is suggested on their site. But that throws me this very long list of 'don't modify props directly error'
<b-collapse v-model="visibile" />
Any idea what I am doing wrong?
EDIT: And an important part I forgot to mention, the error only occurs on initial page load. Afterwards the accordian's are fine to use and work (most of the time).
You can't use v-model with a prop because props are meant to be readonly.
Instead, bind <b-collapse>.visible to the visible prop, and emit the update:visible event with the event data whenever <b-collapse>.input event occurs. The update:visible event updates the parent's visible prop via the .sync modifier.
<b-collapse :visible="visible" #input="$emit('update:visible', $event)">
demo

ReactJS - update component (generated from a list) in the same div

It's a basic question but I searched for a guide without success...
I want to have a list of dropdowns and inputs and each dropdown will change the input next to it.
var list = [{ name: "foo1"}, {name: "foo2"}];
return (
{list.map( (name) => {
return (<div>
<dropdown data={someData}
onChange={(ev) => {
if(ev.value == 'clearIt')
<CHANGE THE NEAR INPUT VALUE>
}
}/>
<input value={name.name} />
</div>)
})});
I don't want to use DOM nor ref cause I understood that it's better to avoid it.
Any suggestions?
Or maybe the ref is the only option?
Thanks
So you can achieve this by doing the following steps:
Create a new component and move the dropdown and input to this new component.
Add state to your component by following this example:
https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
Add an event listener onChange to the dropdown with an event handler which can update the state you created in the first step. (Remember to bind the handler in the constructor.
Add the new component within the div element of this example you gave and pass the relevant data you need to the new component you created.
This should allow you to update only the input next to the dropdown. Also it allows you to have different data for each dropdown you created.

Getting error "avoid mutate props directly" and displaying button

i getting error message when i am passing my prop to component. This props is a to displaying button element in payment. Certain component must not show this button but when i pass the prop all the component that uses this button is hidden here are my code for the parent. My problem is same as this (https://laracasts.com/discuss/channels/vue/using-v-if-to-render-one-template-or-another-based-on-a-props) and the solution does not work for me
<payment :sharedButton="false"><payment>
this is my payment.vue button
<div class="col-lg-auto" v-if="unpaid.qr_code === 1 && sharedButton === true">
<q-btn glossy
size="md"
:label="$t('Common.GetQrCode.Button')"
#click="makePayment(unpaidIndex, true)" color="positive"
>
</q-btn>
</div>
export default{
props: {
sharedButton: {
type: Boolean,
default: true
},
here is the logic that when the sharedButton is false then hide it but when the sharedButton is true then show the button
Expected result:
Button in certain component is hidden
Current Result:
All the component with the button is hidden and get avoid mutate props directly
so i solve the my problem apparently i cannot directly assigned instead i declare a variable called isHidden in data()
data(){
isHidden : false;
}
then declare it by <payment-tab sharedButton = "isHidden">
You are facing the issue as you are directly mutating the prop in the child component and the parent isn't notified about the same. A simple way to solve this is to sync the value of prop in the child and the parent component. So, you can change the value directly in the parent component and since props are reactive the new value of the prop would directly get assigned to the child component.
I am assuming that you'd have an option to change the value back to true in your parent component.
<payment :sharedButton.sync="sharedButton"><payment>
(The second sharedButton would be the value kept in the parent component)
Now, when you want to change the prop inside the child just use
this.$emit('update:sharedButton', false)

How to update the data of a grandchild component in React

So I am using 'react-popout' from https://github.com/JakeGinnivan/react-popout to create a popout window has this subWindow component which has its own data fields in it. I have a MainComponent which defines a list of these popoutwindows (there can be mulitple) and as I define this list I also define that the PopoutWindow has a child subWindow (I leave PopoutWindow component package alone). The PopoutWindow is a wrapper.
So I call the subWindow as part of PopoutWindow inside MainComponent and I want to be able to change the data that I pass into subWindow (currentWindowData) and trigger a re-render but right now it is not working AND I want to only change the data of just one of these PopoutWindows in the list, and not any others.
How can I have it so that upon say a button click, I change the data of only ONE of the subWindows but not all of them (assuming multiple PopoutWindows are rendered and in the list)?
<MainComponent>
openWindow() {
const keyId = shortid.generate();
const window= <PopoutWindow
title={keyId}
options={{height: '700px', width: '350px'}}
key={keyId}
>
{
<subWindow key={shortid.generate()}
data={this.state.currentWindowData}
/>}
</PopoutWindow>;
this.setState({
renderSubWindow: true,
subWindowArray: [window, ...this.state.subeWindowArray],
});
}

Replacing child react component with another based on user intreaction or button click

I have created bootstrap modal component in react.
var carModal=<Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
<CarStructure callbackParent={this.showCarOptionsUpdate}/>
</Modal>
In car structure I have a form where based on button click I want to remove <CarStructure> child component from the modal carModal and update it with another component with different form structure. How can I replace <CarStructure> with another component having totally different user interface and options?
Remember that the job of a React component's render function is to describe how the component should look at any given point at time, so you don't "remove" or "change" pieces of the DOM so much as you describe when they should change themselves. So, you'll want to base the internal component of <Modal> on some sort of state (which may change throughout the life of the parent component). Something like this might do the trick:
var carModalBody;
if (this.state.something) {
var carModalBody = <CarStructure callbackParent={this.showCarOptionsUpdate} />;
} else {
var carModalBody = <SomeOtherComponent />;
}
var carModal = <Modal handleHideModal={this.handleHideCarModal}
onConfirm={this.confirmCarModal}
title="Car"
id="CarModal">
{carModalBody}
</Modal>

Categories

Resources