5

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

Community
  • 1
  • 1
Ben
  • 16,124
  • 22
  • 77
  • 122

2 Answers2

2

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

Community
  • 1
  • 1
Wojciech Bednarski
  • 6,033
  • 9
  • 49
  • 73
  • actually this solution still doesn't solve the real problem which is that the {{outlet}} is not rendered twice. I updated the fiddle by renaming the 'index' script to 'welcome' and you can see it still exhibits the same behavior: http://jsfiddle.net/Benmonro/HmJyu/3/ Also, if I can't name that second script 'index' how can I define that script as the default path in the route? – Ben May 01 '13 at 04:08
  • @Ben you still have more then one id in you DOM, for example login... Another thing is that your state manger has nothing to do with outlet rendering - its in your navbar controller. I guess you can delete state manager code and `if` in the template and when you click login in right top corner you will see welcome message. Second question: Yes you can't have to templates called index is per Ember name conventions. Another thing is better to keep each template in separate file rather then silly script tags, you can register external files like Ember.TEMPLATES[name] = Ember.Handlebars.compile(); – Wojciech Bednarski May 01 '13 at 05:05
  • thanks for the tips, I am a bit of a noob with Ember, I saw ember-tools which I'd like to switch to, but haven't had the time. I was just going off the guides & examples, definitely want to make use of Ember.TEMPLATES. Regardless though, I went through and removed any duplicate IDs, but the problem still exists. I updated the JSFiddle again here. http://jsfiddle.net/Benmonro/HmJyu/4/ The reason I would like to have the outlet work in this way, is that if you are logged out at a certain route (say /posts/1/edit for example) then when you login, you will be right back there. – Ben May 01 '13 at 06:43
  • @Ben as I said in comment above and other response said, you state manager has nothing to do with you login/logout feature. – Wojciech Bednarski May 03 '13 at 01:39
2

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]

harn145
  • 106
  • 5
  • hmm, interesting. i updated my fiddle but it still doesn't work, can you fork and maybe show me what you mean? http://jsfiddle.net/Benmonro/HmJyu/5/ Also the call I added for transitionToRoute("welcome") was just to prove a point, that the outlet doesn't render after the second one. What I *really* want is for the outlet it was on to be back in place... if that's possible. so the process might be like this: user goes to /posts/1/edit (not auth'd) user logs in user is back at /posts/1/edit Or if they were in /posts/new I'd like it to behave the same way... – Ben May 01 '13 at 22:14
  • 1
    I did create a fiddle, but later, seems we crossed paths. As to what you are doing, I ran into the same issues. I am still working through it, but am thinking I got it working by letting the outlet stay the same, and render within the same route. – harn145 May 01 '13 at 22:17
  • cool. i was starting to think maybe I was crazy. I might post this question in the emberjs issues on github... – Ben May 01 '13 at 22:22
  • your fiddle seems to work. the difference is that i wasn't calling transitionToRoute("index") on the logout event. i'll play with this on my app and get back to u... – Ben May 01 '13 at 22:29
  • when you say "letting the outlet stay the same, and render within the same route" what do you mean by that? – Ben May 01 '13 at 22:51
  • well this certainly works better, no doubt about that, but still it would be nice if I didn't have to call transitionToRoute()... – Ben May 01 '13 at 23:09
  • Uhm, yeah, not the best description ever... What I meant was that I do actions on a couple controllers, and not (re)render the route. So just use dynamic templates - {{#if}} and (also) embedded {{view}}s. It's not a completed design yet, though. – harn145 May 01 '13 at 23:09
  • ah ok... actually re-rendering the current route might be exactly what I want. is that possible? – Ben May 01 '13 at 23:11
  • Not sure I understand your question, but using the transitionToRoute() triggers a re-rendering. That's why it wasn't working on your fiddles, because there was no "trigger" to re-evaluate. So information was destroyed, but not rebuild. – harn145 May 01 '13 at 23:30
  • well, i suppose what I meant by that is that I want to 'transitionToRoute(currentRoute)' the question is... what do I use for currentRoute, so that it just goes to whatever route its currently on, without me having to know. – Ben May 01 '13 at 23:37
  • 1
    also, i found that putting the call to transitionToRoute() in an observer works a bit better, as I'll need it to do this AFTER the state changes: (added to my controller) ```, authChanged:function(){ console.log("auth changed"); if(this.get('authState') === 'isAuthenticated') { this.transitionToRoute("welcome"); } else { this.transitionToRoute("index"); } }.observes("authState") ``` – Ben May 01 '13 at 23:38
  • 1
    You should be able to pass the model along to transitionToRoute(), which technically would allow you to land where you left off. Also, you can query the container to see where you are. But I think the latter is not "good practice". I still use it, because I need to influence controllers from outside the App, which (to my working knowledge) will only work along the lines of: var tempController = window.App.__container__.lookup('controller:access'); tempController.set('active', true); – harn145 May 02 '13 at 00:04
  • Hi Ben, if this has allowed you to move on, I would appreciate the bounty being "released" - I would like to be able to comment on stuff, not only my own answers. Thanks! – harn145 May 04 '13 at 13:15
  • Hi Ham, the problem is that this doesn't solve the real problem which is that outlet is only rendered the first time. The transitionToRoute() approach fixes the bug of showing nothing, but it doesn't solve the real issue, which is that it should re-render the current route that the user was in to begin with. If you can answer that, then I'll be happy to give you the bounty. :) – Ben May 04 '13 at 20:06
  • 1
    The design hierarchy is basically route/outlet/view. So a route will render (an) outlet(s) when navigated to. In your example, after my corrections, this is exactly what is happening. You initially weren't logging out, so the route wasn't triggered on what you assumed was a re-login. Maybe you can update your question to reflect your (updated) use case? I am sure we can make it work. – harn145 May 05 '13 at 11:53
  • ok tried to clarify the best I could, hope this helps. and MANY THANKS! :) – Ben May 06 '13 at 06:08
  • so, the short answer is: there's no way this will work nicely - at least not with current code. Outlets are only rendered when the router triggers them. It does a crappy job at that to, because an outlet that's reused doesn't get rerendered either. Only those elements that are bound to a (changed) property will get updated. I just rewrote my app to use regular routing and am moving on. – harn145 May 07 '13 at 02:41