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}}
Related
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 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
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.
While connectOutlet("basename") automatically creates an instance of BasenameController, I was wondering if there's a way to do the same using the {{view}}-helper.
I have tried several things I've seen in examples, but non of them seem to work:
{{view controllerBinding=App.BasenameController}}
{{view controllerBinding=App.basenameController}}
{{view controllerBinding="App.BasenameController"}}
{{view controllerBinding="App.basenameController"}}
I have also tried to do the same using controller instead of controllerBinding, unfortunately without success, and I was also unable to find out where exactly the difference is between the two of them.
Does anybody know how to achieve my goal?
You probably want to use an outlet. The connectOutlet/outlet functions are meant for rending other controller/view pairs.
Lets say we have a person view, but inside that view we want to have another controller/view pair. For this, we need to use a named outlet, our template would look like this.
Person View!
{{name}} = the person's name!
{{controller}} = PersonController!
{{outlet other}} = our outlet
Then inside the router when you want to attach another controller/view to that outlet you can simple use connectOutlet on the personController.
router.get('personController').connectOutlet('other', 'other');
That will wire OtherController and OtherView together and display them in your template. The first param is the outlet name, the 2nd is the controller/view.
This allows you to easily swap different controllers and views onto that outlet. For example, using a different connectOutlet api, we could
router.get('personController').connectOutlet({
outletName: 'other',
controller: router.get('carsController'),
viewClass: App.CarsView
});
...
Btw, to answer you original question. You can get access to other controllers from your view by doing this: {{view controllerBinding="controller.target.otherController"}}. Every controller will have a target property that points back to the router. However, I do not recommend using this code. It's brittle, hard to test, hard to debug, and will come back and bite you in the future.
I was trying to fully understand the previous answer of the question emberjs - how to mark active menu item using router infrastructure
In the answer I tried to simplify (without using a outlet navigation and without adding a second level routing under the root) but in my case the active link doesn't work ://
Here's a fiddle :
http://jsfiddle.net/archange/Scqxw/
What I don't understand in the fiddle is why the "isActive: function()" is not updated after the set on the router... :/
So if someone passing by can explain me the reason. Big Thanks.
And if someone has another solution for handling navigation menu (perhaps using bindAttr ?)
Thanks
What is happening here is that when a template/view creates another view, it gives the newly created view access to it's controller. For example:
<script type="text/x-handlebars" data-template-name="application">
{{view App.NavigationView}}
</script>
The controller of the navigation view is going to be the instance applicationController. This is expected behavior.
If you want to tell your newly created NavigationView to use another controller, just pass that in, like so:
{{view App.NavigationView controllerBinding="navigationController"}}
Please note that I wired these two controllers together in App.ready.
Here is your edited fiddle: http://jsfiddle.net/Scqxw/5/