1

Assume I'm building a blog where the home page renders a list of blog posts. My question is how to pass a model to each child post view?

I have an index.hbs iterating through a collection

{{#forEach models}}
    {{view "post_view" model=value model_name="story"}}
{{/forEach}}

I have a post_view.js

var BaseView = require('./base');

module.exports = BaseView.extend({
     className: 'post_view',

    initialize: function() {
        console.log(this.model); //undefined
        console.log(this.options.model); //undefined on client, logs model attributes on server
    }
});

module.exports.id = 'post_view';

But it appears the model isn't set inside the post_view.js. If I do a {{json value}} inside the {{forEach}} loop I can see the JSONified output printed. What do I need to do to pass a model, do I need to manually construct it inside the view? Thanks!

jaredrada
  • 1,130
  • 3
  • 12
  • 25

3 Answers3

2

I don't have the reputation to comment, but this isn't an answer.

When the subview is initialized often model isn't there yet. It'll certainly be there by postRender() and should be there for getTemplateData(). I don't remember the exact issue with the {{view}} plugin that caused this race condition, but it is something that I've certainly seen before. The wormhole is somewhere around here: https://github.com/rendrjs/rendr/blob/master/shared/base/view.js#L438 and is something that works on the server but not always on the client.

bigethan
  • 48
  • 3
  • Even when I set a breakpoint in the postRender method and inspect the context I can only see the model Id (this > options > fetch_summary (this wasnt there before, cool) > model > and there are two properties the ID and model type (a mongo ID and "story" as expected for my application). Where can I find the rest of the model information? Its not in this > model. – jaredrada Nov 01 '15 at 16:39
1

This is how we've been doing it which has worked well to abstract it a bit further so that we can re-use a 'list' component.

Home Page Controller

index: function(params, callback) {
    var spec = {
        posts: {
            collection: 'Posts',
            params: params
        }
    };
    this.app.fetch(spec, function(err, result) {
        callback(err, result);
    });
}

A Page-level template (eg, home)

<section class="container">
    <h2>Recent Posts</h2>
    {{view "posts/list" collection=posts}}
</section>

Posts List Template (posts/list.hbs)

<div class="media-list">
    {{#each _collection.models}}
        {{view "posts/item" model=this}}
    {{/each}}
</div>

OR if using forEach

{{#forEach _collection.models}}
    {{view "posts/item" model=value}}
{{/forEach}}

Post Item Template (posts/item.hbs)

<div class="media">
  <div class="media-body">
    <h4 class="media-heading">{{title}}</h4>
    {{description}}
  </div>
</div>

I also have this link that I use to try to put together conventions that have worked for us:

https://github.com/crwang/rendr-conventions

Chris
  • 2,537
  • 1
  • 25
  • 22
  • My problem is no where in the view for `posts/item` do I have access to the model. If I log out the params send to the `post/item` view I see the app model but not the model related to that particular item. However with the same log statement the model is printed as expected. Again I'm printing `console.log(this.options.model);` – jaredrada Nov 01 '15 at 16:35
  • How are you initializing the views and subviews? If you follow the way I posted above you should have it in initialize (which you really want since you want to do your `this.listenTo`s in your initialize method. – Chris Nov 02 '15 at 02:03
  • see here https://github.com/jaredrada/rendrjs-demo ... i am following what you have above... but not sure where to explicitly initialize the view. i looked at your conventions page as well. – jaredrada Nov 02 '15 at 14:24
  • and to be clear the template itself renders for each model in the collection as expected. The click event handler works as well (i set it set to log out this.model and the result of that is "undefined"). – jaredrada Nov 02 '15 at 14:44
  • Hi @jaredrada what you have looks like to me that it should work. If you want to chat more, maybe join this channel and we can try to debug it. https://gitter.im/rendrjs/rendr-examples Also, if you would be willing to share the whole project so that I could run it locally, I would probably help you really fast. – Chris Nov 03 '15 at 14:15
0

The answer ended up being the improper use of the parse() method. My original stories collection had a property like this

parse: function(rsp) {
    return rsp.stories;
}

Because the API response contained some metadata as well as an array of stories under the "stories" key. I removed that parse method and instead added

 jsonKey: 'stories'

Which resolved my problem.

jaredrada
  • 1,130
  • 3
  • 12
  • 25