Search code examples
ractivejs

Possible to collapse and expand in ractivejs?


Looking at example

HTML

 <ul>
    <li>Blueberry</li>
    <li>Raspberry</li>
    <li>Pear</li>
    <li>Apple</li>
    <li>Banana</li>
    <li>Cherry</li>
    <li>Mango</li>
    <li>Soursop</li>
    </ul>

Thinking whether it is possible this way in ractivejs

Like this:

<ul>
  {{#each fruit:i}}
   {{#if count > 4}}
    <a href="#" class="less">Show less</a>
   {{else}}
   <li>{{fruit.name}}</li>
   <a href="#" class="more">Show more</a>
   {{/if}}
  {{/each}}
</ul>

If got more items, it would limit only 4 items and display "Show more". Then click on show less after display all item and it will collapse.

Wonder if that is possible? Also would css animation work for class: more and less instead of on-click handlers to expand and collapse? (similar to slide up and down).


Solution

  • Yes, it is possible.

    Collapse and expand is merely tracking who is active, and adding the proper display style to those who are. That can be done with plain templating (see upper half of code).

    The "show more" can be done in 2 ways:

    • If you load your data dynamically (via ajax) per load more, then you can just concat to your existing fruits array and use that for iteration.

    • If your data is already there (you loaded all fruits, yet only want to show a few at a time), you can use a property to track the number of currently displayed, and a computed property to slice the fruits array using that number. Clicking load more will increase that number (say 4 to 8), kicking the computed prop to recalculate using 8 this time.

    Here's an example:

    <ul>
      {{#each slicedFruits:index}}
        <li>
          <!-- Here, clicking the header sets the current fruit to display -->
          <h4 on-click="set('currentFruitIndex', index)">{{name}}</h4>
          <!-- Here, we conditionally apply block or none depending on who's showing -->
          <div style="display:{{if currentFruitIndex === index}}block{{else}}none{{/if}};">{{details}}
        </li>
      {{/each}}
      <!-- using the built-in `add`, we add 4 to `displayedFruits` -->
      <a href="#" on-click="add('displayedFruits', 4)>Load More</a>
    </ul>
    
    <script>
    component.exports = {
      data : {
        fruits: [],            // load up your fruits here
        currentFruitIndex: -1, // change this to any default, -1 for nothing
        displayedFruits: 4,    // change to how many you liked displayed first
      },
      computed: {
        // We slice the main array `fruits` by `displayedFruits`.
        // Changing `displayedFruits` will recalculate this and update the template
        slicedFruits: function(){
          return this.get('fruits').slice(0, this.get('displayedFruits'));
        }
      }
    };
    </script>
    

    As for animation, you can check out Transistions. There's a good example of accordion here.