Handlebars link-to helper doesn't work in an Ember layout - ember.js

I have an Ember layout like this:
{{#link-to 'dashboard'}}
dashboard
{{/link-to}}
testing
{{yield}}
The link-to breaks it, resulting in: Uncaught RangeError: Maximum call stack size exceeded
As a result, nothing is rendered. If I take the link-to out the page renders again. How can I fix this?

In the example you posted above, you are reopening the Ember.View and attempting to apply the layoutName to every single view in the application (which is probably causing some sort of recursive problem as a view may insert a view etc).
If you feel like sharing the layout and don't want to type it a few times you can create a view that has it, and have your other views extend that view
App.MyView = Ember.View.extend({
layoutName: 'layouts/app2'
});
App.IndexView = App.MyView.extend();
http://emberjs.jsbin.com/eHoCeNA/6/edit

Related

Rerender view after change route's dynamic segment

I have a Route with dynamic segment :id. When I change only the dynamic segement part manually in browser url input field, then goes a transition, and all model hooks are called as expected.
The problem is: none of the views are rerendered. I guess it is because only model changed - not the UI. But I have some UI logic in views' didInsertElement handler - reinitialize UI plugins and so on.
How to force ember to rerender view after dynamic segment change?
I agree with the josh's comment. if you are rerendering views with the change of dynamic segment means your code is not written properly. But still if you want to go like that i am gonna give is a part of code.
In your route:
model: function(params){
model.set('id', params.id);
}
In your view which needs to be rerendered:
_modelIdChange: function(){
this.rerender();
}.observes('controller.model.id')
But i don't suggest this. I would rather prefer proper bindings. But i did use rerendering in some cases which mostly when you end up using jquery plugins.

Architecture for reusable object in ember

I am building an admin dashboard using ember. I want to create a reusable chart object of which I can have multiple instances throughout the application. The chart object should have a template consisting of some markup and a canvas element of which I need the id after insertion in the DOM in order to attach the actual chart (chart.js). I have tried several approaches, but I can not seem to figure out the right architecture to do this.
What would be the right architecture in ember to achieve the above?
Thanks!
Ember.Component is your friend
As #raulbrito already mentioned, the best way to go if you want reusable components in ember is indeed to use the new Ember.Component which is heavily based on the new w3 draft for web components and thus beeing future proof.
I've tried to make a simple example on how this could be implemented.
Given a simple route where the model hook returns some static data:
Index Route
App.IndexRoute = Ember.Route.extend({
model: function(){
return Ember.Object.create({
modelOne: data,
modelTwo: data2
});
}
});
data and data2 are simply static objects globally defined for simplicity (as you will see in the demo), but this could be also data coming from a backend or from fixtures etc.
Index template
In the template then we insert our chart component with the line {{line-chart data=model.modelOne}} and as you can see, we also set the data attribute to the index model model.modelOne or model.modelTwo:
<script type="text/x-handlebars" id="index">
<h2>Chart one</h2>
{{line-chart data=model.modelOne}}
<h2>Chart two</h2>
{{line-chart data=model.modelTwo}}
</script>
Component Template
Our component template looks fairly simple because it will render a simple canvas element, but it could be as complex as needed, on how to use Ember.Component please refer also to the docs:
<script type="text/x-handlebars" id="components/line-chart">
</script>
Component Subclass
App.LineChartComponent = Ember.Component.extend({
tagName: 'canvas',
attributeBindings: ['width', 'height'],
width: '480',
height: '360',
data: null,
didInsertElement: function() {
var ctx = this.get('element').getContext("2d");
var myNewChart = new Chart(ctx).Line(this.get('data'));
}
});
Note the naming is important here, Ember knows which subclass powers a component based on its name. For example, if you have a component called line-chart, you would create a subclass called App.LineChartComponent. If your component was called bar-chart-simple, the class name would be App.BarChartSimpleComponent and so on. Ember will look for a class with the camelized name of the component, followed by Component.
So, and since Ember.Component extends from Ember.View we can define all sorts of properties Ember.View supports like tagName. In our case we use canvas because this is what chart.js needs to work. As you can see we have also defined some attributeBindings to control the width and height of the canvas from inside ember. The component has also a data attribute (which could be called whatever you find appropriate) defined on which we later set our model data in the template returned from the IndexRoute model hook. And finally in your didInsertElement hook of our component we initialize the chart passing with this.get('data') the data object to new created Chart.js class.
var ctx = this.get('element').getContext("2d");
var myNewChart = new Chart(ctx).Line(this.get('data'));
And last but not least, please see here for a working example of the above explained.
Hope it helps.
Update in response to your last comment
I've tried to simulate a delay in the resolution of the model hook to mimic a response from a backend, as you can see the template rendering is waiting for the model promise to resolve first. Basically what I've done is to use Ember.run.later with a delay of 2000ms that resolves the promise once timed out:
App.IndexRoute = Ember.Route.extend({
model: function(){
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
var m = Ember.Object.create({
modelOne: data,
modelTwo: data2
});
resolve(m);
}, 2000);
});
}
});
And just for fun I've also added a LoadingRoute to show a spinner while the promise resolution is waiting for data, the LoadingRoute is a less documented feature of ember, you can read more about it here: https://gist.github.com/machty/5647589 under How do I put up a (global) Loading Spinner during a transition w/ Promises?
Plase see here for a updated example: http://jsbin.com/odosoy/145/edit
Update in response to #SamSelikoff's comment
As for the above mentioned LoadingRoute #SamSelikoff pointed out that it's officially documented now: http://emberjs.com/guides/routing/defining-your-routes/#toc_initial-routes
I have some thoughts on this, so just throwing it out there, in case it helps you.
First of all, I would advise you to go and watch Sam Selikoff's presentation on using Ember with D3. All the info here: http://www.samselikoff.com/blog/2013/08/09/ember-d3-simple-dashboards/ . Also, don't miss the comments section on the blog post.
It is a great example on using Ember Views to wrap D3 objects, and can be a good reusable solution. The caveat here is that Ember Views require a backing controller that provides the data. Depending on where in the application you would want to reuse your charts, this might be inconvenience.
The alternative would be to use Ember Components. In that case, you just need to define the Component and associated handlebars template. The good thing about it is that it won't need any backing controller, therefore freeing you from a dependency, which might make it easier for you to add such a component in different places of your application. Without a concrete example, I think it's hard to reach a great conclusion, but maybe this will help you clarify things.

Difference Between controller and controller.content

I have an ArrayController and was using {{#each item in controller}} to iterate over the items in the controller. This was working fine while using the same controller however after switching to another route I ran into some weird behavior which stopped the items from being rerendered. Switching to {{#each item in controller.content}} solved this problem. However I am not sure how this even happened.
What's the difference between controller and controller.content in an each expression (or any where else).
What's the difference between controller and controller.content in an each expression (or any where else).
Basically there is no difference, for example when using an ArrayController which extends from ArrayProxy, then inside the controller this.pushObject(obj) will behave the same as doing this.get('content').pushObject(obj). See here for reference.
But IMO you are better of using model everywhere e.g. {{#each item in model}}.
Check also this answer which I guess will be useful: Ember iterations: when to use #each User, #each user in controller, #each user in model, etc
Hope it helps.

Ember JS - Reference view inside linkTo

I have an Ember JS confusion. First of all I have to admit I'm a bit of an Ember newbie so apologies if this is obvious.
I have the following template:
<script type="text/x-handlebars" data-template-name="threadListItem">
{{#linkTo show thread.receiverLogin}}
<h4>{{thread.receiver.login}}</h4>
<span>{{view.prettyTime}}</span>
{{/linkTo}}
</script>
There's basically a linkTo helper with some elements inside of it.
The weird thing is the {{view.prettyTime}} doesn't display anything when it's inside the linkTo.
However, if I move the span outside the linkTo it finds the view variable ok and it works.
Is there anyway to get access to the view object inside the linkTo?
Christopher is correct that you can access the prettyTime property with:
{{view.parentView.prettyTime}}
Since you're new to ember, it's maybe worth mentioning that in most cases it is best to avoid accessing properties of the view. Instead, consider adding a prettyTime property to your controller. The controller will be the default context for sub-views like the one created by the linkTo helper, so you'll be able to access it with just
{{prettyTime}}
linkTo creates its own view, so the view you want to get access to is the parentView of view.
{{view.parentView.prettyTime}}

Nested Views in Ember

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.