javascriptcanjscanjs-component

How can I access the attribute from the template?


In this example i'm expecting it to say "hello world" but the world isn't picked up from the saying attribute.

(function () {
    'use strict';

    $(function () {
        // Set up a route that maps to the `filter` attribute
        can.route(':filter');

        // Render #app-template
        $('#app').html(can.view('appTemplate', {}));

        // Start the router
        can.route.ready();
    });

    can.Component.extend({
        tag: "say",
        scope: {
            saying: function(){
                return this.attr('saying')
            },
            greeting: 'salutations'
        },
        template: can.view("sayTemplate")
    });

})();

Templates:

<div id="app"></div>

<script id="appTemplate" type="text/mustache">
  <b>Hello</b>
  <say saying="world"></say>
</script>

<script id="sayTemplate" type="text/mustache">
    <b>{{saying}}.</b> <i>{{greeting}}</i>
</script>

Solution

  • You need to tell the component that you want to access the attributes plain value like this:

    can.Component.extend({
      tag: "app-say",
      scope: {
        saying: '@',
        greeting: 'salutations'
      },
      template: can.view("sayTemplate")
    });
    

    See this Fiddle. What you eventually might want to do use an observable attribute from your application state instead of the plain string value. This might look like:

    var appState = new can.Map({
        name: 'World'
    });
    
    $(function () {
        // Set up a route that maps to the `filter` attribute
        can.route(':filter');
    
        // Render #app-template
        $('#app').html(can.view('appTemplate', appState));
    
        // Start the router
        can.route.ready();
    });
    
    can.Component.extend({
        tag: "app-say",
        scope: {
            greeting: 'salutations'
        },
        template: can.view("sayTemplate")
    });
    

    And a template like:

    <div id="app"></div>
    
    <script id="appTemplate" type="text/mustache">
      <b>Hello</b>
      <app-say saying="{name}"></app-say>
      <div><input type="text" can-value="name"></div>
    </script>
    
    <script id="sayTemplate" type="text/mustache">
        <b>{{saying}}.</b> <i>{{greeting}}</i>
    </script>
    

    This also creates a cross-bound input field that will update the name everywhere whenever you update the text field. Fiddle is here.