mikeric / rivets

Lightweight and powerful data binding.
http://rivetsjs.com
MIT License
3.22k stars 310 forks source link

Discussion : enhanced binders #132

Closed fcamblor closed 11 years ago

fcamblor commented 11 years ago

Hi there :-)

I'd like to discuss about a need I had with rivet when starting to use it with BackboneJS.

Often, I need to display a list and, on each list item, a button allowing to edit target list item. Problem is I cannot really have any information about the "context" available during my li node construction.

That is to say, I would love to be able to declare a binder like this :

rivets.binders['jq-scoped'] = function(el){
    $(el).data("rivets-context", /* here, a way to provide rivets context used during my node creation */);
}

Then, it would be used this way :

<ul>
    <li data-each-item="items.models">
        ....
        <button data-jq-scoped="">edit item</button>
    </li>
</ul>

This way, when my button is clicked, I could be able to retrieve rivets' scope used during the creation of the node :

onEditButtonClicked: function(event){
    var context = $(event.currentTarget).data("rivets-context");
    // Then use rivets' context to do things related to clicked entry
}

It would be something similar to jquery template's tmplItem() feature.

My problem : looking at the things we have in hand when defining a custom binders, it doesn't seem feasible (my main concern is to access binder's "context")

Would there be any doc somewhere, helping me ? Or should we consider an enhancement in rivets for this case ?

Thanks in advance for your feedback :-)

mikeric commented 11 years ago

@fcamblor I'm not sure I follow what the problem is exactly. Could you maybe provide a contrived example of where you would need this functionality?

What you're explaining is definitely possible with a simple custom binder (http://jsfiddle.net/MhgQY/2/), but it seems counter-intuitive to use Rivets.js that way. I would probably just create a separate Backbone view for those list items and then manage a separate rivets.bind for them. This should handle your context availability issue instead of trying to use the each-* binder (it is not meant for that particular use-case).

As a side note, Rivets.js is also not meant as a departure from the way you would typically write/structure a Backbone app. It is more of a templating alternative (instead of rendering/re-rendering a static template, you declare bindings between your models and the actual DOM nodes). You'd still want to use Backbone views to manage all the rivets.bind instances and to keep them more focused.

fcamblor commented 11 years ago

I forked your jsfiddle : http://jsfiddle.net/fcamblor/zLGw9/

... and it works perfectly thanks !

Didn't knew about the ":scopedItem" notation, that's exactly what I wanted :-)

What you're explaining is definitely possible with a simple custom binder (http://jsfiddle.net/MhgQY/2/), but it seems counter-intuitive to use Rivets.js that way. I would probably just create a separate Backbone view for those list items and then manage a separate rivets.bind for them. This should handle your context availability issue instead of trying to use the each-* binder (it is not meant for that particular use-case).

I don't really catch your point here. I'm curious and would like to improve my rivets knowledge (there's maybe something I missed here), how would you transform my jsfiddle for this ? (goal is to display scoped item's name when clicking on item's button, inside the view context).

mikeric commented 11 years ago

@fcamblor Since you're only dealing with that one model for the iterated view, and that view wouldn't really have any logic or state of it's own, then using data-each-* is fine in this case, but once those views start getting a little more complex, for example, dealing with the iterated model in relation to other models and the state of the view, etc. it becomes difficult to manage with only a single all-encompassing view and just passing these contexts through the DOM nodes (not very elegant, in my opinion).

Here's how I would do it — I know it seems like more code, but the concerns of the two views are well separated and they contain the appropriate model references. This way you don't need to fuss with storing them on every DOM node that the user interacts with — you just use this.model inside your functions instead of $(event.currentTarget).data("rivets-context").

Hope that makes sense.

fcamblor commented 11 years ago

Ok understood !

I agree with you : passing the context is not very elegant if I had a more sophisticated view. In my case, I only have one button per line, I'll apply the KISS principle but will keep in mind if my "root" view grows in complexity, I'll switch to the aggregated subviews model for better maintenability.

Thanks for your time.