I've setup a State Manager for tracking user login state, based on this answer here: Change Navbar based on login state
However, I'd like to take it to the next step and have not only the navbar update according to the state, but the main template itself. I've gotten this mostly working so that when you click on the login button it will show you the 'welcome you're now logged in message.' However, if you logout and try to login again, it just shows a blank screen as if it is not correctly re-rendering the index route. Here's a JSFiddle with my issue. Notice what happens when you click on login / logout and then login a 2nd time. the 'welcome' message is not displayed.
Here is my index template:
{{render navbar}}
{{authState}}
{{#if isAuthenticated}}
{{outlet}}
{{else}}
{{render login}}
{{/if}}
I can see the 'authState' is correct, but the 'outlet' is not rendered the 2nd time I login...
Here is the complete jsfiddle:
http://jsfiddle.net/Benmonro/HmJyu/1/
CLARIFICATION
#ham asked for a clarification, so here goes:
The main thing I'm trying to accomplish here is that when a state manager changes the state of isAuthenticated then what is currently rendered in {{outlet}} should be swapped out for what is rendered in {{render login}} which could really be any template. The main point is that {{outlet}} will show and hide w/ the state change...
The reason why it doesn't work is because you have two DOM nodes with id index. In your fiddle is extra </script> at the end of HTML pane but it doesn't matter I guess.
ID in DOM must be unique, otherwise you can see some unexpected issues like this one. You can read more here https://developer.mozilla.org/en/docs/DOM/element.id
Here is working fork of your fiddle - http://jsfiddle.net/wbednarski/eMcXq/
BTW, You may find helpful as well - Difference between == and === in JavaScript
You are not transitioning out of your router, but are only changing the state of your LoginStateManager. If you include the routing output in your App creation, you will see the output, and the lack of transitioning out of your "welcome" state.
Just change App to:
App = Ember.Application.create({ LOG_TRANSITIONS: true });
You will see that using your login-button on the navBar will perform the correct function once, where the button on the login form doesn't transition state, and therefor doesn't show the correct result. This is because in the App.NavBarController you perform this.transitionToRoute("welcome").
Just extend all your logins and logouts with:
this.transitionToRoute("welcome") or this.transitionToRoute("index") and it works like a charm.
[edit] Added an example fiddle here: http://jsfiddle.net/AlphaEagle/rGNca/4/ Hope it helps! [/edit]
Related
I'm having a hard time making my router understand that we are on a certain page and it should be displayed in the navigation as active. The situation is as follows:
this.route('mainRoute', function() {
this.route('list');
});
The path we are interested in is /mainRoute. Unfortunately, there are a lot of legacy links that point to /mainRoute/list. The workaround for this was to redirect from the /mainRoute/list component back to the /mainRoute component.
beforeModel() {
this.replaceWith('/mainRoute');
}
Now, my issue is that the /mainRoute navigation link will never be seen as active. I've tried adding a path for the /mainRoute ('/', '/mainRoute', 'mainRoute'), I've tried transforming it to a resource and a bunch of other things that passed my mind. But it either won't work, or will go in an infinite redirecting loop.
Any thoughts on it? Thanks so much, I really need a solution for this!
If the navigation links are {{link-to}} components. There is a current-when property you could use here. It accepts either a boolean or a string. The string is a space separated values with the route names you want this link to be active when.
From the docs
If you need a link to be 'active' even when it doesn't match the current route, you can use the
current-when argument.
<LinkTo #route='photoGallery' #current-when='photos'>
Photo Gallery
</LinkTo>
{{#link-to 'photoGallery' current-when='photos'}}
Photo Gallery
{{/link-to}}
Ember newbie. Using 2.3.0. To an existing application I need to add a button that toggles content on and off the screen. Following the existing code patterns, I added the following two files.
app/components/help.js
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
toggleHelp() {
this.toggleProperty('isShowingHelp');
}
}
});
templates/components/help.hbs
<div class="help">
<a href="#" {{action "toggleHelp"}}>help</a>
</div>
{{#if this.isShowingHelp}}
<p>HELPHELPHELP</p>
{{/if}}
And then in various *.hbs files I'm adding {{partial "components/help"}} to get the button to show up where it is needed.
The button renders as expected as
<div class="help">
help
</div>
But when I click, I get the error, "Nothing handled the action 'toggleHelp'. If you did handle the action, this error can be caused by returning true from an action handler in a controller, causing the action to bubble."
I checked the Ember documentation and saw that this matches the instructions.
I think the issue might be because I am calling it as a partial, but none of the other options (view, render, outlet) seems to apply to my limited case.
As per this answer, I tried {{action "toggleHelp" target='component'}}, but then the error when I click turned into, "ember.debug.js:29112 Uncaught TypeError: Cannot read property 'send' of undefined."
I'm at a total loss... Can anyone point out what I'm missing here? Thanks!
Update:
If I copy toggleHelp into the controller going along with one of the .hbs files, then the link works properly. But surely the right way cannot be to put this in multiple controller files? (And when I try to put toggleHelp in controllers/application.js, in hopes that would cover everywhere (?!), I'm back to the original error.)
Your problem is indeed {{partial "components/help"}}!
In general you should not use partials. To call a component you use {{component-name}}.
However components in Ember 2.3 need to have a - in their name. So help is not valid!
rename your component into something like my-help. So app/components/my-help.js for your js and templates/components/my-help.hbs. Then you can just do {{my-help}} to use the component.
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 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/
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.