Skip to content

Tutorial

Joel edited this page Sep 25, 2016 · 1 revision

Think as you see

Think about Twitter.

"There are some pages in Twitter. If a user is not logged in yet, the first page must be Login. And Login page has some components: Header, Body, Login View, Sign View. Users can login here, and then they may see their Timeline Page."

Here,

  • State: Login, Timeline
  • Components: LoginPage, TimelinePage, Header, Body, Login View, Sign View

Simply we are going to make a simple dummy twitter.

Architecture

When Login state

  • Render LoginPage
  • A user can login filling the login form and click the login button

When Timeline state

  • Render TimelinePage
  • Show Timeline after loading the timeline data from Twitter

Login

Define LoginPage Component

var Component = require('spa-jquery').Component;

Component.define('Login/LoginPage', {
    login : null, //injected
    
    events : {
        click : {
            '.btn-login' : function(e){
                this.login({
                    user_id : this.find('.inp-id'),
                    password : this.find('.inp-password')
                    })
                    .then(this.onLoginSuccess, this.onLoginFailed);
            }
        }
    },

    onLoginSuccess : function(result){
        State.go('Timeline', {
            userId : result.userId, 
            token : result.token
        });
    },
    onLoginFailed : function(result){
        alert('Doh!!');   
    }
});
<div id="loginPage">
    <div>
        <label>ID</label>
        <input type="text" class="inp-id"/>
        <label>Password</label>
        <input type="password" class="inp-password"/>
    </div>
</div>

Define Login State

var State = require('spa-jquery').State;
var Component = require('spa-jquery').Component;
var Promise = Promise ? Promise : require('promise-polyfill');

State.define('Login', {
    $body : null,

    login : function(user){
        return Promise.resolve({
                success:true, 
                userId : 'foo', 
                token:'bar'
                });
    },

    onEnter : function(stateParams, next){
        next();
    },
    
    onState : function(tweets){
        var self = this;
        Component.create('Login').then(function($login){
            self.$body = $login;
            $login.login = self.login;

            Component.getRootComponent().append($login)
        });
    },

    onExit : function(next){
        this.$body.remove();

        next();
    }

});

Timeline

Define TimelinePage Component

var Component = require('spa-jquery').Component;

Component.define('Timeline/TimlinePage', {
    getTweetsMore : null, //injected
    
    $timeline : null,

    render : function(){
        var $this = this;
        Component.create('Timeline/Timeline').then(function($timeline){
            $this.$timeline = $timeline;

            $this.prepend($timeline); 
        })
    },

    event : {
        'scrolldown' : {
            '' : function(e){
                if(! this.isScrollAtBottom(e)){
                    return;
                }

                var timelineState = State.getCurrentState();
                var $this = this;

                this.getTweetsMore().then(function(tweets){
                        $this.$timeline.update({tweets:tweets});
                    });
            }
        }
    },

    isScrollAtBottom : function(e){
        return true;
    }
});
<div id="timelinePage">
</div>

Define Timeline Component

var Component = require('spa-jquery').Component;

Component.define('Timeline/Timeline', {
    tweets : null,

    render : function(){
        var $this = this;
        var tweets = this.tweets; 
        Component.create('Timeline/TimelineItem').times(this.tweets.length)
            .then(function($items){
                $this.empty();

                $items.forEach(function($item, idx){
                    $item.update({tweet: tweets[idx]})
                        .appendTo($this);
                });
            });
    }
});
<ul></ul>

Define TimelineItem Component

var Component = require('spa-jquery').Component;

Component.define('Timeline/Timeline', {
    tweet : null,

    render : function(){
        this.text(JSON.stringify(this.tweet));
    }
});
<li></li>

Define Timeline State

var State = require('spa-jquery').State;
var Component = require('spa-jquery').Component;
var Promise = Promise ? Promise : require('promise-polyfill');

State.define('Timeline', {
    urlPattern : '/users/:userId/timeline',

    ownerId : null,
    pagination : null,
    
    getTweetsMore : function(){
        var self = this;
        return new Promise(function(resolve){
            $.getJSON('api.twitter.com/tweets',{
                owner :  self.ownerId,
                pagination : self.pagination
            }, function(result){
                self.nextPagination();
                resolve(result);
            });
        });
    },

    nextPagination : function(){
        //do somehow
    },

    onEnter : function(stateParams, next){
        this.owner = {
                id : stateParams.userId, 
                token : stateParams.token
                };
        this.getTweetsMore().then(next);
    },
    
    onState : function(tweets){
        var self = this;

        this.tweets = tweets;
        
        Component.create('Timeline').then(function($timeline){
            $timeline.getTweets = self.getTweets;
            $timeline.update({tweets : tweets});

            Component.getRootComponent().append($timeline)
        });
    },

    onExit : function(next){
        this.remove();

        next();
    }

});

Almost done!! Just run it

var SPA = require('spa-jquery');
var State = SPA.State;

State.setDefaultState('Login');
SPA.run();