computed value setter on a component

94 views Asked by At

ref: http://jsfiddle.net/xwLk2vb0/

Person = Ractive.extend({
  template: "<p>the person named {{name}}</p>",
  computed: {
      name: {
          get: function(){
              if(typeof(this.get('_name'))=='undefined'){return "nameless"}
              else{return this.get('_name')}
            },
          set: function(val){
              this.set('_name',val)
            }
      }
  }
});

people_model = new Ractive({
  el: '#people_container',
  template: '{{#people}}<person/>{{/}}',
  data: {
    people: [{},{},{}]
  },
  components :{person : Person}
});

people_model.set('people.0.name','Spongebob')

I can't understand why the last line doesn't invoke the setter on the 'name' computed attribute and then update the rendered templates. Can someone offer any insight, please.

thanks in advance

1

There are 1 answers

1
Rich Harris On BEST ANSWER

The short answer is that computed properties are 'owned' by the component on which they live; you can't interact with them via their parent. I wrote a bit about why that's the case here - it doesn't exactly describe your situation, but the fact is that there's no mapping between the Person component's name, and the name property of the object it relates to. name is effectively shadowed.

This is a Good Thing insofar as it makes code easier to follow and reason about - if an object were populated with additional values just because they coincided with computed properties on a component (i.e, each object in the people array would suddenly get a name: 'nameless' property), you could easily end up in a brain-bending situation trying to figure out where some data came from in your app.

So the solution is to have a 'proxy' computed property that acts as an accessor for the real name property, like so: http://jsfiddle.net/muoz44ec/. Note that we're explicitly linking name inside the component to this.name on the person object.