Search code examples
ractivejs

decorator inside component does is not updated with data


Notwithstanding the advice in this stackoverflow question, I'm still having trouble with decorators being updated with the correct data. Unlike the cited question, now the decorator is inside a component. Here's the code (ref: this jsfiddle):

the html:

<div id="container" />

<script type='template/racive' id='member_template'>
  <p id='name_{{name}}' decorator='sayname:{{name}},{{id}}'>
    {{id}}:{{name}}
    <a href='#'>say my name</a>
  </p>
</script>

and the coffeescript:

Sayname = (node,name)->
  console.log "new decorator: #{name}"
  $(node).find('a').on 'click',->
    alert "I'm saying: #{name}"
  teardown : ->
    console.log "teardown #{name}"
    $(node).off('click')
  update : ->
    console.log "update #{$(node).attr('id')} to #{name}"

Ractive.decorators.sayname = Sayname

Member = Ractive.extend
  template: "#member_template"

window.family = new Ractive
  el : '#container'
  template: "{{#members}}<member name='{{name}}' id='{{id}}' />{{/members}}"
  data:
    members: [{id:1, name:"Barney"},
    {id:2, name:"Fred"},
    {id:3, name:"Wilma"},
    {id:4, name:"Pebbles"}]
  components:
    member: Member

console.log "init complete"

family.set('members',[{id:5,name:"Sneezy"},{id:6,name:"Sleepy"},{id:7,name:"Happy"},{id:8,name:"Grumpy"}])

After initialization and after the dataset is updated, clicking the link with decorator-supplied behaviour still returns the original data, not the updated data.

Any suggestions what is wrong here? Thanks in advance for any insight offered.


Solution

  • Two things:

    1) The decorator function should return an object with both a teardown method and optionally an update method if you want it to be updatable 2) In the update method, the new params are supplied you need to use them to update the decorator state.

    With your example, in my best coffeescript, in would be (see https://jsfiddle.net/964qvry9/1/):

    Sayname = (node,name)->
      console.log "new decorator: #{name}"
      $(node).find('a').on 'click',->
        alert "I'm saying: #{name}"
      decorator =
        teardown : ->
          console.log "teardown #{name}"
          $(node).off('click')
        update : (newName) ->
          console.log "update #{$(node).attr('id')} to #{name}"
          name = newName
    

    For this use case, there's no need to resubscribe to the click event, but often the pattern is helpful for cases where you need to re-run the teardown and init logic:

    function myDecorator( node, param ){
    
        function init(param) {
            //do setup work
        }
    
        function teardown() {
            //do teardown work
        }
    
        init(param);
    
        return {
            teardown() { teardown(); },
            update(param) {
                teardown();
                init(param);
            }
        }
    
    
    }