Ember.js mark active menu binding misunderstood - ember.js

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/

Related

How to prevent views from being destroyed in Ember.js

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!

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}}

How can we load multiple instances into a template?

We're trying to put together a portal, where a layout can have any number of core widgets in any sequence in the main layout.
To simulate this, we've got a number of outlets:
<h1>{{title}}</h1>
{{outlet pos1}}
{{outlet pos2}}
{{outlet pos3}}
{{outlet pos4}}
{{outlet pos5}}
{{outlet pos6}}
{{outlet pos7}}
{{outlet pos8}}
{{outlet pos9}}
{{outlet pos10}}
And in the router, we're attempting to load them in one by one:
connectOutlets: function(router, group) {
router.get('applicationController').connectOutlet('group', group);
router.get('groupController').connectOutlet('pos9', 'toDo', App.ToDo.find(41));
router.get('groupController').connectOutlet('pos3', 'toDo', App.ToDo.find(15));
However, when there are more than one, the final context is used. So in this example, we get two instances of the toDo object, both of which are for id #15.
Am I approaching this in the right way and is it possible to do this programatically, rather than having a fixed layout of outlets?
Thanks,
Dan
Edit: My answer is based on the assumption that this complex solution is really needed in your case. Based on your simple example one could also say, that you could use an ArrayController for all your ToDo items. But here is my try on the answer to the complex problem:
the problem are the following 2 lines:
router.get('groupController').connectOutlet('pos9', 'toDo', App.ToDo.find(41));
router.get('groupController').connectOutlet('pos3', 'toDo', App.ToDo.find(15));
What you basically do there is:
Connect the outlet with name pos9 with the Controller named 'todo'. Set the content of this controller to ToDo with Id 41.
Connect the outlet with name pos3 with the Controller named 'todo'. Set the content of this controller to ToDo with Id 15 (so you are overriding the content of the same controller).
The result is that you end up with both outlets connected to the same instance of a controller. And you the same ToDos since you have set the content property of this single instance twice. The core problem is from my point of view: EmberJS uses single instances of controllers by default.
So my solution approach would be to instantiate a new Controller for each outlet you have. Unfortunately this also requires modification to the lookup of the View. As you likely know, Controller and View are matched by name. So roughly the algorithm would be in pseudocode:
Create new instance of Controller, e.g.: var newController = App.ToDoController.create();
Inject this controller into the router with the appropriate name, e.g. router.set('todoControllerForPos9', newController);
Based on this name, you must enable Ember to find the matching view, e.g. App.set('TodoControllerForPos9View', App.ToDoView);
Finally call connectOutlet on the router, e.g.: router.get('groupController').connectOutlet('pos9', 'todoControllerForPos9', App.ToDo.find(41));
As you might guess, i ran into this problem myself. I did ask this question before and this is the solution, i came up with. I think, this is a missing feature i ember. I call it dynamic outlet names. See my original question here: How to implement a list of multiple elements, where an element can be expanded by click? (Dynamic Outlet Names?)
Have a look at the Update section and the fiddle provided there and you will recognize my pseudo code provided here.
It would be still great, if someone could have a look at my solution, because it is still hacky at the moment, but seems valueable to me. Hope this will gain some attention now with this big answer :-)

Nested view not being destroyed when transitioning to parent

I have an ember application with nested routes but I'm having a problem getting a child view destroyed when transitioning back to the parent route. Probably easiest to look at this fiddle http://jsfiddle.net/j32yT/2/ - it starts by displaying a list of "users"; clicking Create leads to a user creation "form" with a Save button. On save, the action is fired back at the route which transitions back to its parent.
I was hoping that the create view would be destroyed when transitioning away, but it doesn't seem to. Adding in a function to handle the route exit does let me clean up, but it seems a bit messy. Have I misunderstood how the routing works?
UPDATE
By introducing an index route within my users route, I was able to achieve what I wanted - there's a new fiddle here http://jsfiddle.net/AsJca/1/ - am I on the right path here? New to this stuff, so don't yet understand what may constitute best practice!
You have an outlet for Application View and one for UsersView,
<script id="application-template" type="text/x-handlebars">
{{outlet}}
</script>
<script id="users-template" type="text/x-handlebars">
{{#each user in controller}}
{{user.name}}
{{/each}}
<button {{action create_user}}>Create</button>
{{outlet}}
</script>
When you do :
router.get('applicationController').connectOutlet('users');
the outlet of applicationView gets filled with UsersView, but see that the Users View has its own outlet.and when you do router.get('usersController').connectOutlet('createUser'); this outlet is filled with the create new form. So it resides along with the create new button that resides along with the outlet in users-template.
You can change it to,
router.get('applicationController').connectOutlet('createUser');
if you want to replace it, but again think of what you actually need, you know that.

emberjs router #pangratz example class active

#pangratz give a answer in emberjs - how to mark active menu item using router infrastructure
The question is why when i change {{outlet "navigation"}} to {{view App.NavigationView}}, NavigationView.selected is undefined?
I think using {{view App.NavigationView controllerBinding="App.router.navigationController"}} should make your code working. Thanks to this question: connectOutlets from root state called before initialization?