0

I have been trying to understand Emberjs for some time now, I've done the "To Do" application on the Getting Started link, I've read all the documentation and I've coded the blog from the "Ember in Action" book.

Now I am trying to do something on my own and it turns out that I am having all sort of problems so I'll start with the first one on this post.

I have come up with the following templates:

<body>
    <script type="text/x-handlebars" data-template-name="user-navigation">
        <ul id="userNavigation">
            {{#if isAuthenticated}}
                <li>Welcome {{userName}}</li>
                <li>{{#link-to "awesome.index"}}logout{{/link-to}}</li>
                <li><a href="#">Settings</a></li>                   
            {{else}}
                <li>{{#link-to "awesome.login"}}login{{/link-to}}</li>
                <li><a href="#">sign up</a></li>
            {{/if}}
        </ul>
    </script>       

    <script type="text/x-handlebars" data-template-name="awesome/index">
        {{#if isAuthenticated}}
            <section id="userWidgets">
                <div>
                    <button id="createNewWidget">Create New Widget</button>
                </div>
                <div>
                    <ul>
                        {{#each widget}}
                            <li><a href="#">{{widgetName}}</a></li>
                        {{/each}}
                    </ul>
                </div>
            </section>
            <section id="selectedWidget">
            </section>          
        {{else}}
            <div id="welcome">Welcome to my awesome Site. You should sing up!</div>
        {{/if}}
    </script>

    <script type="text/x-handlebars" data-template-name="awesome/login">
        <ul id="mainLoginOptions">
            <li><button class="link-button" {{action 'facebookLogin'}}>Login with Facebook</button></li>
        </ul>
    </script>

    <script type="text/x-handlebars" id="application">
        <header id="siteHeader">
            <div id="logo" class="index-logo">My awesome SPA</div>
            <div id="userData" class="index-userdata">
                {{render "user-navigation" user}}
            </div>
        </header>
        <section id="mainContent">              
            {{outlet}}
        </section>
        <footer id="footer" class="index-footer"><div class="index-footer-content">Copyright 2014</div></footer>
    </script>
</body>

Basically it is a header at the top with "log in/signup" or "log out/settings" links depending if the user is logged in or not. And in the main content section a "Welcome" message or the logged in user's content.

I am trying to figure out how to handle the log in workflow so the header template renders correctly and the main content renders with the user's data. I was looking at this link to get ideas but I still have a lot of questions about how to pull it off.

My JavaScript code looks like this:

window.Awesome = Ember.Application.create({
    LOG_TRANSITIONS: true
});

Awesome.Router.map(function() {
    this.resource("awesome", {path: "/"}, function(){
        this.route('login');
    });
});

Awesome.AwesomeLoginRoute = Ember.Route.extend({
    actions:{
        facebookLogin: function(){
            var router = this;

            Awesome.User = Ember.Object.create({
                id: "1",
                isAuthenticated: "true",
                userName: "Serge"           
            });

            router.transitionTo('awesome.index');
        }
    }
});

Not much but, based on that link, I am setting a "User" object that is defined directly in the application but I do not know how to send it to the templates so that they use it to render themselves correctly.

Of course the idea is that at some point I will be using a service to get the tokens from different social networks but the first step is to understand how Ember works and for that I am trying to stub the object.

Any pointers are very much appreciated.

Sergio Romero
  • 6,477
  • 11
  • 41
  • 71

2 Answers2

1

You have two options that I can think of.

The first option is to use the User object directly in the template. Handlebars templates in Ember.js interpret capitalized variable names as globals. So in your template, you should be able to do something like this:

{{#if Awesome.User.isAuthenticated}}{{/if}}

Option two is to use that object as the model for the route that you want to use the data in. For example:

Awesome.AwesomeIndexRoute = Ember.Route.extend({
    model: function() {
        return Awesome.User;
    }
});

Now the context of your awesome/index template is your user object, so your code above should work.

{{#if isAuthenticated}}{{/if}}

The former approach is a bit easier for a beginner, so I would recommend that for now. As you begin to understand Ember.js more, you'll see some better patterns for that, but baby steps, right? :)

Also, you're setting the isAuthenticated property to "true" (string value). You should probably use a boolean value. "true" will work how you expect, but "false" is a truthy value in Javascript (all non-empty strings are), so your else case will never be executed.

GJK
  • 37,023
  • 8
  • 55
  • 74
  • Thank you for your answer but unfortunately none of these options seemed to work. When I tried returning the model from the AwesomeIndexRoute I tried calling {{render "user-navigation" user}} and {{render "user-navigation" model}}, neither work. There is not any other code in play only what I have included in the post. What could I be doing wrong? – Sergio Romero Mar 06 '14 at 15:31
  • The [former](http://emberjs.jsbin.com/payohuke/1/edit?html,js,output) seems to work ok for me. The latter can get a bit hairy when using things like the render helper, which is why I suggested the former. – GJK Mar 06 '14 at 15:39
  • Something strange is going on. By trying several things I ended up with the first option ONLY ON THE "AWESOME/INDEX" template and it worked BUT if I fully qualify the object in the exact same way on the "_user-navigation" partial then neither of them work. If I try the second option again only checking the "AWESOME/INDEX" template and removing the conditional in the partial again it works but as soon as I re-add the conditional it stops working. – Sergio Romero Mar 06 '14 at 19:13
  • I'm not sure what's going ton there. Can you reproduce the issue in a JSBin? – GJK Mar 06 '14 at 20:20
0

Turns out quite a few things had to happen to make this work.

In order to find the answer I took:

  • GJK's answer.
  • The links on the accepted answer from this post.
  • This blog also on authentication using Ember.

After putting everything together I came up with the following:

The templates changed a little bit:

<body>
        <script type="text/x-handlebars" data-template-name="_user-navigation">
            <ul id="userNavigation">
                {{#if Awesome.authToken}}
                    <li>Welcome {{Awesome.User.userName}}</li>
                    <li><button class="link-button" {{action 'logout'}}>logout</button></li>                    
                    <li><a href="#">Settings</a></li>                   
                {{else}}
                    <li>{{#link-to "awesome.login"}}login{{/link-to}}</li>
                    <li><a href="#">sign up</a></li>
                {{/if}}
            </ul>
        </script>       

        <script type="text/x-handlebars" data-template-name="awesome/index">
            <div id="welcome">Welcome to my awesome Site. You should sing up!</div>
        </script>

        <script type="text/x-handlebars" data-template-name="awesome/login">
            <ul id="mainLoginOptions">
                <li><button class="link-button" {{action 'facebookLogin'}}>Login with Facebook</button></li>
            </ul>
        </script>

        <script type="text/x-handlebars" data-template-name="widgets">
            <section id="userWidgets">
                <div>
                    <button id="createNewWidget">Create New Widget</button>
                </div>
                <div>
                    <ul>
                        {{#each Awesome.User.widgets}}
                            <li><a href="#">{{widgetName}}</a></li>
                        {{/each}}
                    </ul>
                </div>
            </section>
            <section id="selectedWidget">
            </section>                  
        </script>

        <script type="text/x-handlebars" id="application">
            <header id="siteHeader">
                <div id="logo" class="index-logo">My awesome SPA</div>
                <div id="userData" class="index-userdata">
                    {{partial "user-navigation"}}
                </div>
            </header>
            <section id="mainContent">              
                {{outlet}}
            </section>
            <footer id="footer" class="index-footer"><div class="index-footer-content">Copyright 2014</div></footer>
        </script>
    </body>

And the JavaScript code became this (note the use of localStorage and the global variable in the application):

window.Awesome = Ember.Application.create({
    LOG_TRANSITIONS: true,
    authToken: localStorage['authToken']
});

Awesome.ApplicationRoute = Ember.Route.extend({
    actions:{
        logout: function(){
            var router = this;

            Awesome.set('authToken', null);
            delete localStorage['authToken'];
            router.transitionTo('awesome.index');
        }
    }
});

Awesome.Router.map(function() {
    this.resource("awesome", {path: "/"}, function(){
        this.route('login');
    });
    this.resource("widgets");
});

Awesome.AwesomeLoginRoute = Ember.Route.extend({
    actions:{
        facebookLogin: function(){
            var router = this;

            //First call a service that authenticates the user and returns the token.
            Awesome.set('authToken', '123456789');

            //Then add the logic which will get the user's data. Most likely it should be a transition to another route.
            Awesome.User = Ember.Object.create({
                id: "1",
                userName: "Serge",
                widgets: [{widgetName: "Great Widget"},{widgetName: "Fantastic Widget"},{widgetName: "Brutal Widget"}]
            });

            router.transitionTo('widgets');
        }
    }
});

This exercise still needs a lot of work but at least the authentication piece is starting to look good, hopefully this will help others.

Community
  • 1
  • 1
Sergio Romero
  • 6,477
  • 11
  • 41
  • 71