3

I'm using Rivets.js for two two-way data binding in a Backbone project and would like to implement iteration binding. The documentation suggests iteration binding is possible, but there are no examples available. I am using a simple Rails API to send JSON to the client and want to iterate over the contents. Has anyone had any success getting this functionality working in Rivets.js?

Reference material: Simple Example using Backbone.js and Rivets.js

jsFiddle here: http://jsfiddle.net/rhodee/3qcYQ/1/

From the Rivets.js site

Iteration Binding

Even though a binding routine for each-item will likely be included in Rivets.js, you can use the data-html binding along with a set of formatters in the interim to do sorting and iterative rendering of collections (amongst other cool things).

<ul data-html="model.tags | sort | tagList"></ul>
Community
  • 1
  • 1
rhodee
  • 1,257
  • 1
  • 14
  • 27
  • Cab you explain what do you mean with _"to implement iteration binding"_? – fguillen Aug 07 '12 at 21:23
  • I'm looking for a method similar to #each in ruby and emberjs. Simply put I would like to iterate over a model object and create DOM elements – rhodee Aug 07 '12 at 21:30

4 Answers4

3

Expanding on this answer:

As of 0.3.2 there is now a data-each-[item] binding for exactly this purpose.

Note that you will need to specifically modify your Rivets adapter to work with a Backbone Collection, as the out-of-the-box examples on the Rivets.js site do not fly with this use case.

You'll need something like this in your rivets.configure({ adapter: ... }):

...
read: function( obj, keypath ) {
    return obj instanceof Backbone.Collection 
       ? obj["models"] 
       : obj.get(keypath)
}

And the JS Fiddle: http://jsfiddle.net/tigertim719/fwhuf/70/

For bonus points, Collections embedded in Models will require additional handling in your adapter.

For more information, check this post on Rivets.js Github issues:
Binding to Backbone.Collection with the data-each- binding

papercowboy
  • 3,369
  • 2
  • 28
  • 32
2

As of 0.3.2 there is now a data-each-[item] binding for exactly this purpose.

<ul>
  <li data-each-todo="list.todos">
    <input type="checkbox" data-checked="todo.done">
    <span data-text="todo.summary"></span>
  </li>
<ul>

For previous versions of Rivets.js, the work-around that you've referred to is to implement the iterative rendering with a formatter — for example you would have a data-html binding with model.items | itemList where the itemList formatter just loops over the array and returns some rendered HTML.

rivets.formatters.itemList = (array) ->
  ("<li>#{item.name}</li>" for item in array).join ''
Michael Richards
  • 1,791
  • 14
  • 19
1

UnderscoreJS is integrated in Backbone so you can use its native methods like _.each() or use the integrated Backbone Collection underscore methods.

Is it this what you are looking for?

fguillen
  • 36,125
  • 23
  • 149
  • 210
  • I suppose I can wrap the forEach method and pipe it in data-attr call in the template. But is that the correct way to address this? – rhodee Aug 08 '12 at 17:19
0

cayuu's answer was correct. But the rivets.js reference in the fiddle was not working, so the result is not displaying.

Check out the version below to see the action.

http://jsfiddle.net/tigertim719/fwhuf/70/

rivets.configure({
  adapter: {
    subscribe: function(obj, keypath, callback) {
      obj.on('change:' + keypath, callback);
    },
    unsubscribe: function(obj, keypath, callback) {
      obj.off('change:' + keypath, callback);
    },
    read: function(obj, keypath) {
        return obj instanceof Backbone.Collection ? obj["models"] : obj.get(keypath);
    },
    publish: function(obj, keypath, value) {
      obj.set(keypath, value);
    }
  }
});

The most important part is

read: function(obj, keypath) {
            return obj instanceof Backbone.Collection ? obj["models"] : obj.get(keypath);
        },

That tells rivets how to read your collection and model from Backbone.

Tim Hong
  • 2,734
  • 20
  • 23