gmac / backbone.epoxy

Declarative data binding and computed models for Backbone
http://epoxyjs.org
MIT License
615 stars 89 forks source link

Make EpoxyBinding public and usable outside of Epoxy.View? #83

Closed maxpoulin64 closed 9 years ago

maxpoulin64 commented 10 years ago

(Sorry for the long text, I think I can't be clear without that much context :/)

== Issue == I think a great addition to Epoxy would be to have a way to manually apply/manage bindings outside of Epoxy's own applyBindings() function. Currently, the only way to ever add a binding to the page is to have a view and have applyBindings do it, but it's kind of a black box: there's no way to access the EpoxyBinding objects. I'm thinking of something that would look like this: var myBinding = new Exoxy.Binding.MyHandler($element, model, modelProperty, options); that would behave pretty much exactly like the current bindings but much more flexible. It opens a way to do fancy stuff like access its state, pause listening, force refresh, binding handler extensions (Epoxy.bindings.collection.extend()?).

== Why? == Why would I ever want to access that, you may ask? I got multiple situations where I needed to pass more parameters to a binding handler and communicate with it. For example, the "collection" binding handler: I am in a situation where I need to access all the views managed by a collection handler to query their viewModel. I currently work around it by using the model instead and set _myView property on it, but it's an ugly solution as I could possibly have multiple instances of the same view pointing on the same model, with each different state.

== Example == Here's a simplified example using the good old TODO list: There is a TodoListModel that contains a few properties like name and createDate, as well as a BackboneCollection of TodoItemModel which contains the actual TODOs { title: 'Something something', description: 'Lorem ipsum dolor sit amet...'}. Then I have a TodoListView with a "collection:$collection" binding with an itemView of TodoItemView. TodoItemView has a ViewModel that contains a expanded property that indicated if the task's description is shown or not. Everything works perfectly until I need to add a "Expand all/collapse all" button to the TodoListView. There's no way to ever loop over all TodoItemViews and update their viewModel property. A parent view have no way to communicate with their child views so I can't query their document position, make them flash or anything unless I store their viewModel seperately and maintain two collections instead of one. That's where having a way to manually apply the bindings comes handy: I could, in my initialize function, create a new collection handler myself, store a reference to it and loop over its view hash when needed. Bonus: it would finally make it possible to have multiple collections with different itemView.

== Fixing it == I first thought of just making EpoxyBinding public by adding it to the Epoxy object, but EpoxyBinding takes a lot of arguments and relies on prior initialization by a bunch of other private functions. If I want to implement this, I will have to refactor a lot of stuff inside the EpoxyBinding object (like bindElementToView) so it is all standalone and self-contained. I think this will have many side benefits as well (maybe get rid of the hackish exceptions for optionsXXX and events handlers). Would you be willing to accept such a large pull request? Or am I better just fork it and maintain my own fork? Or maybe there's another solution I didn't see?

gmac commented 9 years ago

An interesting through, however I think that you're assuming internal Epoxy constructors have more autonomy than they really do. They are encapsulated within the Epoxy closure because they rely heavily on internal library configuration. Taken out of context of their internal implementation, they wouldn't do very much.