Knockout SPA

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

by WizKid81

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-3.2.0.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<body>
  <!-- Folders -->
  <ul class="folders" data-bind="foreach: searches">
    <li data-bind="text: $data, 
                       css: { selected: $data == $root.chosenSearchId() },
                       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.searches = ['Queue', 'Active', 'Completed'];
  self.chosenFolderId = ko.observable();
  self.chosenSearchId = 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('#:search', function() {
      var search = this.params.search;
      //self.chosenFolderId(folder);
      self.chosenSearchId(search);
      self.chosenMailData(null);

	///This is a dummy ajax call that just returns the same JSON data passed to it.  Then the success function is called to process that JSON to load the data for display.  In real application, would make a call to a Search web service to get the real data back
      $.ajax({
        type: 'POST',
        url: '/echo/json/',
        data: {
          json: JSON.stringify({
            search: search
          }),
          delay: 0
        },
        success: function(data) {
        	console.log("data: ", data);
          self.chosenFolderData({
            mails: fakeData["Inbox"]
          });
        }
      });
    });

    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() {
     ...