Closed tliao closed 10 years ago
After looking at it some more, I think this is correct (albeit inconvenient) behavior. I was rendering TestView's el into AppView during initialize. AppView calls applyBindings as the last step in its construction. Since the binding was in the html, AppView finds the binding in its el and tries to bind it again.
I'm running into this as well - did you find a good solution for this case?
@adamyonk: Here's what I use personnaly:
Epoxy.binding.addHandler('view', {
init: function($element, view) {
this.$original = $element;
this.$view = $element;
},
set: function($element, view) {
var $newEl = view ? view.$el : this.$original;
// We use .after() + .detach() to avoid jQuery
// unbinding Epoxy's handlers on the child view
this.$view.after($newEl);
this.$view.detach();
this.$view = $newEl;
},
clean: function() {
// Will cause "view" to be null so set() will put back the original element
this.set(null, null);
}
});
It's a custom handler that just replaces the element it is bound to with the actual View. The view has to be in the binding context for this to work (inside a model or directly in bindingSources). Since the bindings of the parent view are already queried the problem is avoided and they will never interfere.
@adamyonk: It's been a while and I can't find my sample project, so this is a little hand-wavy. The general idea was to not insert the child view's el
onto the parent view's el
until after the parent view completes initializing (which will call applyBindings()
).
I instantiate all the views in initialize
, but don't render anything onto the page yet. Initialize
also sets up a callback on the model to render on some event firing. Parent views call their child view's render
and add the child view's el to its own el. Since the epoxy bindings have already been applied, this issue is avoided.
ParentView.js
Epoxy.View.extend({
initialize: function() {
// Only instantiate the child view, do *not* render the child view.
this.childView = new ChildView();
// Causes the render to be triggered separately from the initialization of the parent view
this.model.on('change:id', this.render, this);
},
render: function() {
// Both render the child view *and* put the child view's el onto the parent view's el
this.$('#child-view-container').html(this.childView.render().el);
return this;
}
});
ChildView.js
// No render on instantiation
Epoxy.View.extend({
render: function() {
// Whatever rendering you need to do here.
return this;
}
});
Thanks for the recommendations! I ended up just mixing in the Epoxy.View
to a regular Backbone.View
, so that I could call applyBindings()
before the parent view's initializer is finished.
@maxpoulin64 : I know it is long time you have posted this solution but if possible can you give an example on how to use this handler
I found a situation where a collection binding is throwing an exception because a parent view does not have the binding source.
I have a child view (TestView) whose el includes a collection$collection binding. TestView sets collection in the constructor. When the parent view (AppView) creates a new instance of TestView (i.e.
new TestView()
), Epoxy tries to apply the bindings. However, since AppView does NOT have collection set, I get the following:I would have expected the applyBindings call on construction of TestView to be in the context of TestView rather than AppView.
Let me know if there's anything else I can do to help. I created a small project that demonstrates this if you need it and I can also provide a full stacktrace.