learn.knockoutjs.com - single page applications

http://learn.knockoutjs.com/#/?tutorial=webmail

by Shobhit Sharma

HTML

<link rel="stylesheet" href="http://learn.knockoutjs.com/Content/App/coderunner.css">
<link rel="stylesheet" href="http://learn.knockoutjs.com/Content/TutorialSpecific/webmail.css">
<script src="http://learn.knockoutjs.com/scripts/lib/sammy.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-2.2.1.js"></script>
<body>
    <!-- Folders -->
    <ul class="folders" data-bind="foreach: folders">
        <li data-bind="text: $data, 
                       css: { selected: $data == $root.chosenFolderId() },
                       click: $root.goToFolder"></li>
    </ul>
    
    <!-- Mails grid -->
    <table class="mails" data-bind="with: chosenFolderData">
        <thead><tr><th>From</th><th>To</th><th>Subject</th><th>Date</th></tr></thead>
        <tbody data-bind="foreach: mails">
            <tr data-bind="click: $root.goToMail">
                <td data-bind="text: from"></td>
                <td data-bind="text: to"></td>
                <td data-bind="text: subject"></td>
                <td data-bind="text: date"></td>
            </tr>     
        </tbody>
    </table>
    
    <!-- Chosen mail -->
    <div class="viewMail" data-bind="with: chosenMailData">
        <div class="mailInfo">
            <h1 data-bind="text: subject"></h1>
            <p><label>From</label>: <span data-bind="text: from"></span></p>
            <p><label>To</label>: <span data-bind="text: to"></span></p>
            <p><label>Date</label>: <span data-bind="text: date"></span></p>
        </div>
        <p class="message" data-bind="html: messageContent" />
    </div>
</body>

JavaScript

function WebmailViewModel() {
    // Data
    var self = this;
    self.folders = ['Inbox', 'Archive', 'Sent', 'Spam'];
    self.chosenFolderId = ko.observable();
    self.chosenFolderData = ko.observable();
    self.chosenMailData = ko.observable();

    // Behaviours    
    self.goToFolder = function(folder) { location.hash = folder };
    self.goToMail = function(mail) { location.hash = mail.folder + '/' + mail.id };

    // Client-side routes    
    Sammy(function() {
        this.get('#:folder', function() {
            var folder = this.params.folder;
            self.chosenFolderId(folder);
            self.chosenMailData(null);
            
            $.ajax({
                type: 'POST',
                url: '/echo/json/',
                data: {
                    json: JSON.stringify({ folder: folder }),
                    delay: 0
                },
                success: function(data) {
                    self.chosenFolderData({ mails: fakeData[folder] });
                }
            });
        });

        this.get('#:folder/:mailId', function() {
            var folder = this.params.folder,
                mailId = this.params.mailId;
            
            self.chosenFolderId(folder);
            self.chosenFolderData(null);
            
            $.ajax({
                type: 'POST',
                url: '/echo/json/',
                data: {
                    json: JSON.stringify({ mailId: mailId }),
                    delay: 0
                },
                success: function(data) {
                    self.chosenMailData(ko.utils.arrayFirst(fakeData[folder], function(item) {
                        return item.id == mailId;                                              
                    }));              
                }
            });
        });
    
        this.get('', function() { this.app.runRoute('get', '#Inbox') });
    }).run();    
};

ko.applyBindings(new WebmailViewModel());


//Fake data for jsFiddle...