From my main handlebars dashboard template I am rendering multiple templates in a loop, setting the model as following
{{#each forecastDispatch in forecastDispatches}}
{{render "balance.forecastDispatch" forecastDispatch}}
{{/each}}
The dashboard combines multiple models and renders them on the same page/route.
From logging to the console, I can see that the BalanceForecastDispatchController controller gets instantiated correctly for each render call and the forecastDispatch model of type DispatchType is set as content, but not as model, model is still undefined. As the model is not populated properly, passing data to lower level components does not work. I thought that the model is just an alias/proxy for content, hence I am quite surprised.
What am I missing here? Any help is really appreciated, I am trying to solve this for quite some time now, but cannot find the culprit.
The issue was caused by snippets in my Handlebars template which were not commented out properly. As a result, one extra instance of the BalanceForecastDispatchController was created by Ember. This controller had off course no model/content assigned to it. In the Chrome Ember-inspector the controller was shown without a model.
Related
I have an ArrayController (documents) which displays a list of ObjectsControllers (document) for its content.
My ArrayController template (Documents):
{{#each document in model}}
{{render "document" document}}
{{/each}}
The issue I am facing is that the "sortProperties" and "sortAscending" properties on the ArrayController are no longer having any effect. I assume this is because I am looping "model". If I loop "each document in controller", the document ObjectControllers dont seem to get the model assigned to them as a call to .model then throws an undefined error. Should I be looping "controller" or "model"? If the answer is model, how can I sort it and if the answer is controller, how can I get the model set on each controller?
Rather than modifying the base model, the sorted collection is exposed as arrangedContent.
To explain why it's arrangedContent rather than arrangedModel, in Ember's ControllerMixin content is defined as an alias for model, but it used to be the other way around.
You may have to set the itemController property on your ArrayController (Documents).
See here: http://emberjs.com/api/classes/Ember.ArrayController.html
Edit: Also, you had it right the first time with {{#each document in controller}}. Doing it straight from the model will ignore configuration in your controller, which includes sorting rules you may have.
Quick note:
I don't believe this is a duplicate of Ember.js: Prevent destroying of views. Other related questions that I've found are out-of-date.
In case this becomes out-of-date later, I am using Ember 1.7.0 with Handlebars 1.3.0.
Context for the question:
As the title states, I am wondering how to transition between views without destroying them. Using queryParams does not solve my issue.
I am creating a calculator with the following nested views:
>>Calculator View
>>Report View (hasMany relationship to Calculator)
--School Partial (I am using queryParams here)
I am able to navigate between the Report views just fine without destroying my School partial, since I am using queryParams and using a displaySchoolPartial boolean to show/hide the partial. Example below:
Report template (stripped to only show the essential part):
<script type="text/x-handlebars" data-template-name="calculator/report">
...
{{#link-to "calculator.report" (query-parameters displaySchoolPartial="true")}}
{{render "_school"}}
</script>
School template (also stripped down):
<script type="text/x-handlebars" data-template-name="_school">
{{#with controllers.calculatorReport}}
<div {{bind-attr class=":schoolPartialWrapper displaySchoolPartial::hide-element"}}>
...
</div>
{{/with}}
</script>
This works as expected. Navigating between different Report views and School partials, as stated before, does not destroy the view.
The problem:
My problem comes when navigating to the Calculator view, the Report view is destroyed, which then destroys my School view. I do not want to also use queryParams to replace my Report views.
The reason I need to make sure the views aren't destroyed is because I have a select box with 3,000 schools in my School partial. It takes too long to re-render this. It would be a much better UX to simply show/hide the Report views.
Don't fight with Ember. You will lose.
Views are instantiated and rendered when needed and torn down when done.
Why do you have a 3000-element dropdown, anyway?
If you really, really want to do this, what I would suggest is putting a {{render}} on your application page, and hide it. The view will be created and rendered when the app comes up and persist as long as the app is alive. Then, in the didInsertElement of your view, do a cloneNode of that hidden element and insert it into the view's DOM somewhere. You may have to muck around getting event handlers wired up correctly.
My suggestion is not using "render" but using "partial", so you only need to drop in the template that you want. Have a control variable that set show/hide via css class. And control that variable using you controllers.
Using "partial" will allow you to have school template independent from report, thereby removing report will not affect school.
Just make sure you define the outlet and partial correctly.
Hope it helps!
I am working on a bit of code to show a D3 chart using Ember fixture data as the source for the data. The charts show up just fine on the first load of the page but if I move to a different route & then return to the first route (the one with the working chart) the chart simply disappears. So I guess my question is, how do I get the chart to appear every time the route is visited? Here is what my Route and View code looks like, will add more code if requested.
Updated with JS Bin: http://jsbin.com/ihapaz/2/edit
The route may not be getting any data when you return back to it. When using linkTo the model hooks are not fired. The setupController is called directly with the model that you pass to linkTo. However if the route depends on the model hook having fired to load it data then the view would be empty as it wouldn't have any data to render.
That's the only thing that comes to mind from the above code. Try posting a jsbin if this doesn't work.
Edit: Post jsbin
After looking at your jsbin I realized my earlier answer was incorrect. In general it is true that linkTo skips the model hook, but only if dynamic segments are present. Your route has no dynamic segments. Hence the model hook will always be called, so the view/chart is getting data correctly.
The error is in your implementation of render. The purpose of the render method is to push strings of html onto the DOM. This isn't the appropriate place for custom DOM insertion. For that you need to put things on the didInsertElement method.
I made these changes, renaming render to didInsertElement and the corresponding updateChart. Here's the updated jsbin.
I am working on my first significant Ember.js app, and have been running into some roadblocks. After hitting one-too-many show-stopping bugs with ember-data, I have decided to roll my own models using Ember.Object (for now at least - ember-data looks like it will be real awesome, real soon).
My basic model structure is:
Album (has photo album-specific attrs, and references a collection of images)
Images (an ArrayProxy collection of Image models, which tracks collection-level attrs like 'currentImage', and 'nextImage')
Image
I have a {{#linkTo}} helper in my template that is supposed to allow the user to click to the next image in the set, like so:
<button>
{{#linkTo image controllers.images.nextImage}}
Next Image
{{/linkTo}}
</button>
This template has the context of the AlbumController, which needs: ["images"]. controllers.images.nextImage is a computed property, that figures out ID of the currently-displayed image, then uses it to find the Image model for the next model in the Images ArrayProxy collection.
My problem is this:
Upon page load, I receive an error message Uncaught Error: assertion failed: Cannot call get with 'id' on an undefined object.
I'm assuming this is because the {{#linkTo}} helper is trying to get the id property from the return of controllers.image.nextImage, which is a computed property that relies on the Images collection being loaded from the server. This async behaviour is being handled with promises behind-the-scenes, but the {{#linkTo}} helper seems to required a valid context to be returned immediately upon page load.
My questions are these:
Has anybody else had to handle this kind of situation, where they're not using ember-data and had to use {{#linkTo}} helpers with computed properties that weren't immediately available?
Can anyone suggest workarounds that don't fight Ember's way of doing things?
Some of my thoughts are:
make the computed property return a dummy context, that somehow gets replaced with a valid model after load
use an {{#action}} helper instead of {{#linkTo}}
I have written up a JSBin example which is mostly code-complete, except I couldn't manipulate the hash URL to trigger the nested routes, so I had to do everything in the application template.
I've got the need for a recursive nested set of views in Ember. Basically think of it as a file structure with folders.
I thought I could do it with render, but that didn't work. Inside structures/show view:
{{#each child in structures}}
{{ render 'structures/show' child }}
{{/each}}
I get the error:
Uncaught Error: assertion failed: This view is already rendered
I read in another SO Question about using the {{view}} helper:
{{#each child in structure.structures}}
{{ view App.StructuresShowView structureBinding='child'}}<br>
{{/each}}
But this doesn't render properly. Possibly because the example is too old?
How do I properly render the same view (and controller?) with a different object in order to build a nested/recursive view? Is there a better way than the object directions?
Thanks.
Update. Looks like itemControllerClass might be what I'm looking for? Still trying to figure it out.
I think you cannot call {{render}} multiple times on a single route. If you need to create something many times, you probably need to use {{control}}, which is the same as {{render}} with a difference that {{render}} has one controller (singelton) and {{control}} has a new controller every time it's called.
Here's an open issue related to your question.