Skip to content
This repository has been archived by the owner on Jan 12, 2018. It is now read-only.

Controller.loaded doesn't work as expected for non-trivial templates #107

Open
wojtha opened this issue Aug 5, 2014 · 4 comments
Open

Comments

@wojtha
Copy link

wojtha commented Aug 5, 2014

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?

@jnicklas
Copy link
Collaborator

jnicklas commented Aug 6, 2014

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.

@wojtha
Copy link
Author

wojtha commented Aug 6, 2014

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

@jnicklas
Copy link
Collaborator

jnicklas commented Aug 6, 2014

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.

@wojtha
Copy link
Author

wojtha commented Aug 6, 2014

Oh, yeah, thats it! Thank you Jonas!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants