Search code examples
recursionmustacheractivejs

Ractive recursive partials with couter


I had some problem when I used recursive partials. I tried to create comments which every one can comment again, like this:

comment (depth 0)
  comment (depth 1)
    comment (depth 2)

I want to add some special classes for different depth of comments

 {{#messages}}
      {>message}
    {{/messages}}
    <!-- {{>message}} -->
    <div class="{{getClasses()}}"">{{text}}</div>
      {{incrDepth()}}

      {{#comments}}
        {{>message}}
      {{/comments}}

      {{decrDepth()}}
    <!-- {{/message}} -->

This is additional function which I use

{
  data: {
    incrDepth: function () {
      this.depth++;
    },

    decrDepth: function () {
      this.depth--;
    },

    getClasses: function () {
      return 'depth' + this.depth;
    }
  }
}

So, before every comments I increase depth and after comments I decrease it. But unfortunately all my invokes of getClasses() return 'depth0' and I can't understand why.


Solution

  • It helps if you think of templates as being read-only - rather than 'executing' the template from top to bottom, Ractive constructs a virtual DOM from the template, and updates nodes within it whenever they need to change. For that reason, there's no guarantee about when a given function will be called.

    So you should avoid functions with 'side-effects' - they should be for retrieving data, never setting it.

    But a recursive structure is definitely possible - you need to use inline components. A component is a nested Ractive instance that manages its own data, and it's easy to set a depth property to 'whatever the parent depth is, plus one' - try running the code snippet below to see it in action.

    Ractive.components.comment = Ractive.extend({
        template: '#comment',
        data: { depth: 0 } // default
    });
    
    var ractive = new Ractive({
        el: 'main',
        template: '#template',
        data: {
            comments: [
                {
                    author: 'alice',
                    content: 'FIRST!'
                },
                {
                    author: 'bob',
                    content: 'first!!1!',
                    children: [
                        {
                            author: 'bob',
                            content: 'argh alice beat me',
                            children: [
                                {
                                    author: 'alice',
                                    content: 'haha'
                                },
                                {
                                    author: 'charles',
                                    content: 'you snooze you lose'
                                }
                            ]
                        }
                    ]
                },
                {
                    author: 'larry_34xj',
                    content: 'Thank you for this article, it is very interesting. Please visit my blog at http://pills4u.com'
                },
                {
                    author: 'dawn',
                    content: 'This article is terrible. I don\'t know where to begin',
                    children: [
                        {
                            author: 'bob',
                            content: 'do you have nothing better to do than write snarky comments on blog posts?',
                            children: [
                                {
                                    author: 'dawn',
                                    content: 'Do you have nothing better to do than write "first"? loser',
                                    children: [
                                        {
                                            author: 'bob',
                                            content: 'touché'
                                        },
                                        {
                                            author: 'alice',
                                            content: 'haha pwned'
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }        
            ]
        }
    });
    body { font-family: 'Helvetica Neue', arial, sans-serif; font-weight: 200; color: #353535; } h1 { font-weight: 200; } p { margin: 0.5em 0; }
    
    .comment {
        padding: 0.5em;
        border-top: 1px solid #eee;
    }
    
    .comment .comment {
        padding-left: 2em;
    }
    
    .depth-1 {
        color: #555;
    }
    
    .depth-2 {
        color: #999;
    }
    <script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
    
    <main></main>
    
    <script id='template' type='text/ractive'>
        <h1><a href='http://ifyoulikeitsomuchwhydontyougolivethere.com/' target='_blank'>spEak You're bRanes</a></h1>
        
        {{#each comments}}
            <comment comment='{{this}}'/>
        {{/each}}
    </script>
    
    <script id='comment' type='text/ractive'>
        <article class='comment depth-{{depth}}'>
            <p><strong>{{comment.author}}</strong> wrote:</p>
            <p>{{comment.content}}</p>
            
            {{#each comment.children}}
                <comment comment='{{this}}' depth='{{depth + 1}}'/>
            {{/each}}
        </article>
    </script>