Closed nfm closed 9 years ago
Hey, thanks for the feedback. At the moment, Epoxy does rely on the template existing within the element's DOM. This is a really tricky situation that I fought with while setting it up, and I do agree that the final outcome is only mediocre.
The fundamental issue here is where the template text comes from, and how it gets provided to a binding. Obviously, we can't put a template into a binding declaration; that would be craziness... so, the options are that we lift the template from the element (which is how this is implemented), or else we provide a reference to the template text through the binding. To do that, we're reliant on some kind of model field to hold the template... which is generally where Epoxy's viewModel
idea is headed: a sanctioned model for holding view data.
If you have any suggestions here on how you'd like to be able to better use templates, I'm all ears for an API enhancement.
Thanks for the detailed reply @gmac.
I'm not sure if I have anything particularly insightful to add - I'm still getting my head around the epoxy.js internals.
My initial thought would be to override the view's render
function instead of the constructor
function, use the same super
handling there as in the current constructor
override, and call applyBindings()
last, so it would be the user's responsibility to populate $el
in their render
function. Then the collection binding handlers could be modified to call before
and append
with view.render().$el
, instead of just view.$el
.
Of course, this approach would break the case where the template is already within the element's DOM, and the user never calls render()
because they don't need to. There are probably other complexities at play here that I haven't picked up on too!
I'm not sure if it helps in your case, but here's what I'm doing: Backbone allows the el
property to be a function. You can return your template string from this function.
Actual example:
var templateCache = {};
var template = function(name) {
return function() {
return templateCache[name] || (templateCache[name] = $('template#' + name).html());
};
};
views.TodoItemView = Backbone.Epoxy.View.extend({
bindings: 'data-bind',
el: template('todoItemTmpl')
});
This way the template will be looked up right when the view is instantiated. Backbone will wrap the string in a jQuery object, which will cause the outer most/first element to become the element of the view.
Edit: You can see this here in the Backbone code
http://backbonejs.org/docs/backbone.html#section-129
Ensure that the View has a DOM element to render into. If this.el is a string, pass it through $(), take the first matching element, and re-assign it to el. Otherwise, create an element from the id, className and tagName properties.
Awesome, I like what @prinzhorn said. Let's go with that. While it's a little kludgy, Epoxy is specialized enough that its goal is not to be the ultimate template renderer (especially now, with tools like React available).
just a comment for the record.
I worked on this problem too, for collections (the binding). I think that, to keep the BB spirit, el should be the result of a call to render()
currently applybinding() actually takes the el as it is, not giving a change to the view to change the content. (maybe calling it in the constructor is too early?)
regarding the cache handler, the best would be to borrow the Marionnette's which is perfect. you can override the tmplaite engine & the loading method. That's what I use.
http://marionettejs.com/docs/marionette.templatecache.html
First up, I'm loving epoxy.js - it rocks. Thanks!
I'm just getting started with it so I'm not sure if I'm doing it wrong, but I'm having to work around a few issues that seem to stem from the assumption that the template will already be in the DOM, or that the view's el will be set to an existing DOM element.
Here's a simplified version of the kinds of views I'm writing:
So the template is a function (I'm using
haml_coffee_assets
but I expect this is an issue with any template compilation). In the above example, if I havedata-bind
attributes in the template, I need to call@applyBindings()
after populating@$el
for epoxy to do its thing.I hit another problem when binding collections - adding to the collection ends up running something like
$element.append(view.$el)
- andel
won't have ever been populated from my template, so I get an empty div appended.In the docs, most of the views seem to either target an existing DOM element in the page (
el: '#some-id'
) or use an inline template (el:"<li><input type='checkbox'> <input type='text' class='todo'></li>"
).Have I missed the correct way to handle this? Is this a valid use case to support, or am I about to go down a bad path here?
Thanks!