Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return resolved data models in view callback #183

Closed
basememara opened this issue Nov 29, 2012 · 12 comments
Closed

Return resolved data models in view callback #183

basememara opened this issue Nov 29, 2012 · 12 comments

Comments

@basememara
Copy link

It would make sense to add the resolved data models in the callback of the view like this:

 can.view('todos/todos.ejs', { 
    todos: Todo.findAll(), 
    user: User.findOne( { id: 5 } ) 
}).then(function(frag, data){ 
    me.element.html(frag); 
    //myFunction(data.todo); 
});

The data parameter does not exist in the API like above, but it would open doors if it could. Passing the data in the callback on line 361 of view.js did not work. Please see this forum thread for more details: https://forum.javascriptmvc.com/topic/get-model-in-view-callback-28-11-2012

@rjgotten
Copy link

rjgotten commented Dec 3, 2012

👍
This would really help with a few of my use cases, where I have additional post-rendering logic that depends on values from the model.

@daffl daffl closed this as completed in a6141c0 Dec 3, 2012
@justinbmeyer
Copy link
Contributor

This doesn't really seem needed. You can easily use $.when and get the data and use it to render.

Sent from my iPhone

On Nov 29, 2012, at 1:52 PM, Basem Emara notifications@github.com wrote:

It would make sense to add the resolved data models in the callback of the view like this:

can.view('todos/todos.ejs', {
todos: Todo.findAll(),
user: User.findOne( { id: 5 } )
}).then(function(frag, data){
me.element.html(frag);
//myFunction(data.todo);
});

The data parameter does not exist in the API like above, but it would open doors if it could. Passing the data in the callback on line 361 of view.js did not work. Please see this forum thread for more details: https://forum.javascriptmvc.com/topic/get-model-in-view-callback-28-11-2012


Reply to this email directly or view it on GitHub.

@daffl
Copy link
Contributor

daffl commented Dec 3, 2012

I don't know, this:

var todosDfd = Todo.findAll(),
    userDfd = User.findOne( { id: 5 } ),
    viewDfd = can.view('todos/todos.ejs', { 
        todos: todoDfd, 
        user: userDfd 
    }).then(function(frag, data){ 
        me.element.html(frag); 
        //myFunction(data.todo); 
    });

can.when (todosDfd, userDfd, viewDfd).then(function(todos, user, frag) {
    // To stuff here
});

is a pretty awkward contraption compared to

can.view('todos/todos.ejs', { 
    todos: Todo.findAll(), 
    user: User.findOne( { id: 5 } ) 
}).then(function(frag, data){ 
    me.element.html(frag); 
    //myFunction(data.todo); 
});

And all it takes to make that possible is to add the data as the second parameter when resolving the deferred.

@justinbmeyer
Copy link
Contributor

I would think maybe:

$.when( 
  Todo.findAll(), 
   User.findOne({id: 5})
  can.view.get('todos/todos.ejs') )
  .then(function(todos, user, renderer) {
  el.html( renderer( {todos: todos, user: user} )
  // myFunction(todos, user)
})

@daffl
Copy link
Contributor

daffl commented Dec 3, 2012

Doesn't that defeat the purpose of being able to pass Deferreds when rendering a view? I do like the way Can handles Deferreds in an unobtrusive way and you don't have to worry about control flow (can.when, dfd.done, dfd.fail etc.) when there is no need to.

And the only thing it took to allow accessing the resolved data was changing deferred.resolve(result); to deferred.resolve(result, data);.

The other changes were actually fixing an issue because can.view modified the original data:

var viewData = {
    todos : Todo.findAll()
};

can.view('view.ejs', viewData).done(function(frag) {
    viewData.todos // -> resolved data
});

viewData.todos // -> can.Deferred

I'm pretty sure that the original object shouldn't just change at some point in time (without even having a way of finding out when and how).

@maurerbot
Copy link

I saw this being resolved in 1.1.3 but when I tried updating my code by removing the model callback, "data" is not returned and is undefined. I am wondering if the original suggestion is what was actually implemented or the above comment from @daffl would be the proper way? It is a nice suggestion since the code looks nicer as well without the model callback.

...
can.view('js/view/lineup.ejs', {
    stories:  StoryModel.findAll( {section: section.name}, function (resp) {
        console.log('resp', resp);
        //the resp is a dependent for a story lookup. Update the sections observeable to fire the call for a lineup story
        $APP.CURRENT_SECTIONS.attr(section.name, resp); 
    }),
    lineup: section.name
} ).then(function (frag, data) {
    console.log('data', data); //<- undefined
    $('#section'+k).append(frag);
});
...

@basememara
Copy link
Author

I can confirm there is a problem with this too and the data indeed comes back undefined. Stepping thru the code shows that the correct data values does get passed back to the callback function, but I think jQuery deferred functions take over and the data is no longer in scope by the time it gets back to you?

Thanks for the discussion on this. This addition does make code flow much more smoother.

@daffl
Copy link
Contributor

daffl commented Dec 12, 2012

This is the test used for implementing the feature:

https://github.com/bitovi/canjs/blob/master/view/view_test.js#L192

If you can provide a breaking test we can try and figure out why it isn't working.

@maurerbot
Copy link

So the problem occurs only when you don't use the render method.

Does not work.

can.view('js/view/lineup.ejs', { ...

Does work.

can.view.render('js/view/lineup.ejs', { ...

@basememara
Copy link
Author

I just saw the same thing: http://jsfiddle.net/basememara/j9XSw/6/

@rjgotten
Copy link

So the problem occurs only when you don't use the render method.

And no wonder: can.view internally wraps the result value from can.view.render with a piped Deferred that only preserves the first parameter. It discards any others.

See: https://github.com/bitovi/canjs/blob/f120881f312ecd854de36a89a83e9b7de7ed8c33/view/view.js#L13-L40

@daffl
Copy link
Contributor

daffl commented Dec 13, 2012

True indeed. Unfortunately you can't just pipe deferreds that resolve with more than one argument.

Anyway, can somebody please create a new issue for this (making the resolved data available when using can.view)?

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

No branches or pull requests

5 participants