Search code examples
javascriptractivejs

Reading computed properties in Ractive.js


I'm trying to figure out what the best way of achieving this is. I might be thinking about it in the wrong way, but this is what I "want" to achieve:

<div>
    {{#if selection}}
        <div>There is a selection in Component!</div>
    {{/if}}
    <Component />
</div>

where selection is a computed property in Component that I want to consume in the outer scope. Is there any way of referencing the property of the component instance?

For example:

<div>
    {{#if foo.selection}}
        <div>There is a selection in Component!</div>
    {{/if}}
    <Component id="foo" />
</div>

Or is this the wrong way of thinking about it. The only other way I can think of is to use events instead.

<div>
    {{#if selection}}
        <div>There is a selection in Component!</div>
    {{/if}}
    <Component on-selection="select" />
</div>

But that's not as elegant since it requireextra code:

ractive.on("selection", function(e) { this.set("selection", ...); });

Solution

  • Starting in version 0.8 you can directly map the event to the data value (see http://jsfiddle.net/0zubyyov/) which nicely decouples the component internals from the parent:

    template:

    <script id='template' type='text/ractive'>
        {{#if selected}}selected!{{/if}}
        <component on-select='set("selected", $1)'/>
    </script>
    
    <script id='component' type='text/ractive'>
        <input type='checkbox' on-change='fire("select", event.node.checked)'>
    </script>
    

    javascript:

    Ractive.components.component = Ractive.extend({
        template: '#component',
        data: { selected: false }
    });
    
    var r = new Ractive({
        el: document.body,
        template: '#template'
    });
    

    Using 0.7 you might consider passing in a value to the component that's kept up to date (see http://jsfiddle.net/gr6d7vs8/). I was more explicit in this one about handling a computed property:

    <script id='template' type='text/ractive'>
        {{#if selected}} selected! {{/if}}
        <component selected='{{selected}}'/>
    </script>
    
    <script id='component' type='text/ractive'>
        <input type='checkbox' checked='{{checked}}'>
    </script>
    

    javascript:

    Ractive.components.component = Ractive.extend({
        template: '#component',
        data: { checked: false, allowed: true },
        computed: {
            isChecked () {
                return this.get('checked') && this.get('allowed')
            }
        },
        oninit(){
            this.observe('isChecked', isChecked => {
                this.set('selected', isChecked);
            });
        }
    });