serenade.js
serenade.js copied to clipboard
Controller.loaded doesn't work as expected for non-trivial templates
Controller.loaded doesn't work for templates with multiple root nodes, especially when there are some DynamicNodes.
template.serenade:
form[class="form-inline" event:submit=search!]
...
- if @searchTopicsCount
...
- else
"No results were found."
- in @pager
...
controller.coffee:
class SearchController
loaded: (view, model) ->
console.log(view, model)
Expected input to loaded
is view, model
, however the argument list for this template is:
<form>
undefined
undefined
model
The related code in View.prototype.render
is following:
if (typeof controller.loaded === "function") {
controller.loaded.apply(controller, __slice.call(nodes.map(function(node) {
return node.element;
})).concat([model]));
}
So first three arguments are product of node.element
and this property is not defined for DynamicNodes
build for @searchTopicsCount
or @pager
, thats why the second and third argument is undefined.
How this is suppose to work? I expected compiled view as the first argument but instead of that I got node list in first three arguments for this particular case. I need to hookup after view is rendered to initialize jQuery UI Sortable on the result set since I'm preloading the result set when the app is initialized. Is there a better way? Something like "view rendered" event?
Hmm, that's a good question. I think when we added this feature we didn't really consider what would happen if root nodes were dynamic nodes. So far we aren't really exposing Node objects to the user, so sending those in isn't great either. I suppose we could simply remove all undefined items before we send in to the callback, but that's not very intuitive either.
What about moving loaded callback later in the execution flow or introducing new rendered
callback?
I'm experimenting with this now:
if (!skipCallback) {
if (typeof controller.rendered === "function") {
controller.rendered.apply(controller, [fragment, model]);
}
}
return fragment;
};
return View;
and in controller:
class MyController
rendered: (fragment, model) ->
console.log(fragment, model)
I'm trying also to use fragment = Serenade.document.createElement('div');
since DocumentFragment
can't be used as jQuery argument since its API is too basic and lacks needed selectors.
What I'm trying to achieve is something like:
class MyController
rendered: (fragment, model) ->
$('tbody', fragment).sortable
I think you might have an easier time adding a tbody[on:load=someControllerCallback]
in your view. It's not super-well documented that this is possible right now, but it's easier for cases like this.
Oh, yeah, thats it! Thank you Jonas!