rendrjs / rendr

Render your Backbone.js apps on the client and the server, using Node.js.
MIT License
4.09k stars 312 forks source link

this.collection is empty on client side code when initial page render is on server #399

Open demircancelebi opened 10 years ago

demircancelebi commented 10 years ago

Hi, I am developing an app with rendr and I am showing some search results in my list.hbs page. It looks like this:

{{# if models.length }}
  {{# each models }}
    {{ view 'listing/list-single' model=this }}
  {{/ each }}
{{/ if }} 

and let's say my listing/list-single.hbs page looks like this:

<h2>{{ title }}</h2>
<p>{{ description }}</p>

in the list-single.js file, I cannot access this.model in client side code if the initial page render is on server. I mean, I can access it in getTemplateData function, but cannot access it in postRender. I can also access this.model if the page is rendered on client, so I think something is broken here.

bigethan commented 10 years ago

No 100% sure but give this a try:

{{ view 'listing/list-single' _model=this }}
mikepuerto commented 10 years ago

I believe you would actually want to do something like:

{{#if _collection.length}}
  {{#each _collection.models}}
    {{ view 'listing/list-single' model=this }}
  {{/each}}
{{/if}} 

models is just an array of standard objects. _collection is an actual instance of the collection with the models you want to pass to your subviews..

demircancelebi commented 10 years ago

Thanks to both of you, @bigethan and @mikepuerto . Neither of your solutions solved the issue. I suspect this issue arose when a view is called from another view. I also have another page where I show a single listing, and I can access this.model in both server and client on that page. I still cannot access this.model in list.hbs though if the initial page render is on server. (I can access it in my 2nd search, when rendering takes place in the client)

mikepuerto commented 10 years ago

That's odd. I am actually doing this exact same thing and it works like a charm. Is it actually rendering the subviews? I have actually seen this issue before where it worked in one place and not another... turned out to be error on my part though... What version are you using?

demircancelebi commented 10 years ago

this is the version I am using: git://github.com/rendrjs/rendr.git#c599674a87f9044da959d5f2381147f5ce95aebe. What is yours?

demircancelebi commented 9 years ago

My further examination showed that I can access the attributes of this.model in postRender when I fetch a model in controller and pass it to view, but when I fetch a collection in controller and pass that collection to view, I can see the rendered results on page, but this.collection seems to be empty in client side code. (it is not empty in server side code though)

To summarize this issue, it looks like this.collection is an empty collection in client side code when initial page render is on server side. Don't you have the same issue @mikepuerto @bigethan ? And if not, what is the version you are using?

demircancelebi commented 9 years ago

Don't you have the same issue? @saponifi3d and @sarchila, you might have some ideas about this one maybe?

sarchila commented 9 years ago

Try passing the model_name into the view helper as well. Is the model a Listing model? If so, try

{{ view 'listing/list-single' model=this model_name='Listing' }}
demircancelebi commented 9 years ago

Well, it turns out that problem is not about the templates or the loop. I can summarize it as: this.collection is an empty collection in client side code when initial page render is on server side.. So, when I log this.collection in getTemplateData, I can see the collection in terminal and it passes to templates as expected. I log it again in postRender, and it is empty. This problem only occurs when initial page render is on server though. When I come from another page, I can access this.collection in both getTemplateData and postRender.

sarchila commented 9 years ago

Tried to reproduce this, but I am not seeing the symptoms that you describe here. For reference, though, I am using the newest version of Rendr: git://github.com/rendrjs/rendr.git#43262635f6c82a888598ebb1ce78af86b803678e

It might be that this is fixed by the newer version, or that I am not able to reproduce the issue accurately.

mikepuerto commented 9 years ago

when I ran into this issue here https://github.com/rendrjs/rendr/issues/390 - I ended up having to go with a different approach being that the amount of help here is scarce. Can't even get @spikebrehm to join any conversation anymore. I've gotta be honest, if there were another, more stable framework... I'd switch in a heartbeat instead of putting all the tim and energy into making changes to the code that they will likely not except a pull request for anyway... -mike (frustrated).

demircancelebi commented 9 years ago

@sarchila I still have the same issue at that version. @mikepuerto Although I think they would accept a PR which fixes this issue, I feel exactly the same about a more stable framework (which is non-existent AFAIK at the moment).

saponifi3d commented 9 years ago

i think the this scope will be a bit weird in this context. https://github.com/rendrjs/rendr-handlebars/blob/master/shared/helpers.js#L82 sets the scope of the each helper to be a modified version of a model's attributes to include _app and other oddities.

I made a forEach helper that allows me to pass a key and value so i can iterate objects or models as a whole. @sarchila is also correct in that you'll need to pass a model_name for client-side routing to work correctly as the step where rendr grabs the model from the model store it needs to know what model it's trying to grab, not just the id.

extra note: let me know what are some of the biggest bugs you guys are running into, and i'm going to start devoting more of my time to fixing those bugs and updating the documentation of rendr. hopefully this will be getting a lot more stable quickly!

saponifi3d commented 9 years ago

@demircancelebi - i'm working on a PR to rendr-handlebars to add the forEach helper I wrote.

Are there any additional helpers you think might be good to have for everyone?

demircancelebi commented 9 years ago

Hey, As I mentioned in later posts in this thread, main issue seems to be not about each helper. My problem is that this.collection is an empty collection in client side code when initial page render is on server side. It only happens when initial page is rendered on server. this.collection is accessible in server side code, so it passes through getTemplateData to .hbs template, but it is empty in postRender or any other function triggered by a user action for that matter. Same kinda logic works fine with this.model though. (@saponifi3d, I also saw that you work at Change.org, I am not sure if you do not see the bug that I see, - maybe it has something to do with my default UI language (Turkish) -, but your project pages keeps refreshing itself. You can send me an email if you cannot reproduce.)

saponifi3d commented 9 years ago

interesting that it works in this.model but not this.collection - i think the problem might be with the hydration step here: https://github.com/rendrjs/rendr/blob/master/shared/base/view.js#L482

Which is something i noticed in my last commit to Rendr. For some reason it's never actually doing the creation of a collection if it's passed a json object or something - which might make it so it's not passing through to the template data correctly.

I'll take a gander at the code and see if i can't reproduce / fix this bug for ya! (if nothing else, i'll fix it so it will always at least return a collection).

sarchila commented 9 years ago

@demircancelebi I thought the way @por framed this issue (https://github.com/rendrjs/rendr/issues/350) was super helpful because he demonstrated how to reproduce the issue on the 00_simple example app from this repo.

If you have some time, would you be able to give a couple of steps on how to reproduce this on that sample app, for instance? I've been trying with no luck to reproduce this issue (been trying with a view and a subview that had a collection passed in).

demircancelebi commented 9 years ago

Ok, I will do that in the next 24 hours :)

azriel46d commented 9 years ago

Has anything been done on this?

I have the same issue where models generated on the server are not bound to their view on the client side. This is the scenario:

The builder view i have has a model which contains a list of models for its children similar to the following json

{
"_id": "01234567",
"title" : "My Model",
"elements": {
"12abc213": { "paramA" : "xxxx", "paramB" : "xxxx",  "modelToUse" : "modelA" },
"798xzv78": { "paramA" : "xxxx", "paramB" : "xxxx",  "modelToUse" : "modelB" }
}

now in the builder.getTemplateData' i'm going through the elements and creating the appropriate models according the elements and bound to the particular element with amodel` key (and i even do a model.store()). the using the templates i have something as follows

{{#if elements}}
            {{#each elements}}
                {{view 'some/view/path' model=model}} 
            {{/each}}
    {{/if}}

however on the client side, these models are not found in the modelStore nor are they attached to the view

---EDIT I tried to move it up to the controller and created a collection from the nodes, on the server the collection and its models is available in the view, whilst on the client side the view's model is undefined .However this time they are available in the model store

---EDIT 2 Still using the collection i finally managed and the key to it was to make the collection hold polymorphic models.

saponifi3d commented 9 years ago

@demircancelebi @azriel46d and @mikepuerto

do you have the idAttribute set to _id on the model?

if so you should only need to do view 'some/view/path' model=model model_name="ModelName" - it needs both an id and a model_name to re-create an instance of the model (or grab it from the store).

My guess is that it just needs to be able to grab the instance from the store or rebuild it with the constructor, and those two things are requirements for doing that.

roelvanhintum commented 9 years ago

Is there a solution for this issue? The conversation has died, but the problem remains. I'm running into the same issue.

edit: Turns out that i was overriding the parse function on the collection instead of using the jsonKey. Now the collection is parsed without any problem.

roelvanhintum commented 9 years ago

It looks like this bug isn't a rendr bug at all. In my case it was poor coding on my end. Maybe it is time to close this with the note to check what code is overridden in.