4

I have a component which displays has a prop called obj. obj has two properties: obj.title and obj.body. Each is bound to a textfield so as to be reactive and editable.

<div id="app">
  <controller :obj="{title: 'TITLE'}"></controller>
</div>

<template id="controller">

  <input type="text" v-model="obj.title">
  <p>{{ obj.title }}</p>
  <input type="text" v-model="obj.body">
  <p>{{ obj.body }}</p>

</template>

The title property is part of the prop which is bound to the component. But the body property has been added dynamically during the created callback. Here is the js:

Vue.component('controller', {
  template: '#controller',
  props: ['obj'],

  created: function() {
    this.obj.body = "BODY";
  },
});

new Vue({
  el: '#app',
});

The problem is that the body property isn't behaving reactively. Changes to the body textfield are not reflected by {{ obj.body }}.

The vue website has a section about Adding and Deleting Properties, but I couldn't get their suggestions to work.

Here is a jsfiddle demonstrating the problem.

Note: it has been suggested that I declare the body property at the same time as the title property. This would work, but for my use-case the property needs to be added dynamically.

2 Answers 2

1

Try to declare the body property when passing the prop:

<controller :obj="{title: 'TITLE', body: null}"></controller>

Or in your created method:

created: function() {
    this.obj = {
        title: this.obj.title,
        body: 'some body
    }
},

https://jsfiddle.net/crabbly/33721g9w/

Sign up to request clarification or add additional context in comments.

3 Comments

That would work, but for my use case I won't know if the property will be called body, or even if any extra properties will be added until the component has been been created. I've edited the question to clarify.
Interesting, I can't see why a component would create different properties like that, but I updated the answer with a solution that should work for you. Check it out.
I accepted my own solution because it explains why reactivity was broken, and provides a solution for the most general case. Thank you for your help, you pointed me in the right direction.
1

I have selected this as the Accepted solution because it is what I would recommend to someone else with the same problem.

As user crabbly noticed, the reactivity can only be re-established if the prop's reference is updated.

I think the nicest way to do this is by making a shallow copy:

created: function() {
   this.obj.body = 'BODY'
   /**
    * ... other code that adds other properties and messes around with obj...
    */
   this.obj = Object.assign({}, this.obj);
}

... here, Object.assign is responsible for updating the reference.

This solution is currently not supported by IE, though any "clone" function will do (e.g. this.obj = jQuery.extend({}, this.obj); also works).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.