Knockout SPA Ajax loaded templates

I am lost between the possibilities offered to handle this case: let's say we have the following constraints:

  • Knockout
  • SPA with Sammy.js - Html loaded via Ajax

My page:

+-------------------------------+
| #navigation                   |
+---------+---------------------+
| #sidebar|    #content         |
|         |                     |
|         |                     |
|         |                     |
+---------+---------------------+

Currently, I have one appViewModel which handle the data-bind for all the shared elements of my website: #navigation and #sidebar. This appViewModel has observable used on every pages of my website.

appViewModel = function () {
    var self = this;
    self.sidebarItemArray = ko.observableArray([x, y, z]);
    self.currentRoute = ko.observable();

    ...

    self.updateView = function(path, currentRoute) {
        return $.get(path, function( data ) {
            var $data = $(data);
            // Updates #content, TITLE and update the currentRoute observable.
            $( '#content' ).replaceWith($data.find('#content'));
            document.title = $data.filter('title').text();
            self.currentRoute(currentRoute);
            }, 'html');
    }

    Sammy(function() {
        this.get(':link'', function() {
            self.updateView(this.path, this.params.link);
        });
    }).run();
}
ko.applyBindings(new appViewModel());

Now, let's say that #content is a piece of DOM loaded through an Ajax Call. Each time a user click a link inside #navigation or #sidebar, Sammy.js intercept it and then update #content. The problem is that the new DOM inside #content has data-bindings itself.

1) First, should I use the html data-bind on #content, replaceWith(as above) or the template binding with custom function to get the template? (http://knockoutjs.com/documentation/template-binding.html#note-5-dynamically-choosing-which-template-is-used)? What is the best practice here?

2) Should Sammy necessary lives inside the appViewModel as in the documentation or elsewhere is just fine?

3) Once the updateView method is completed, how would you bind the new DOM? Like below? Isn't there a risk of rebinding some DOM because ko.applyBindings has already been called without second argument?

ko.applyBindings(new routeSpecificViewModel() , document.getElementById("content")); 

I am thankful for your help.

Answers


One simple solution is to make the page's viewmodel an observable, and load it ondemand. Use a variable to record if ko.applyBindings has been called. Example from the knockout-spa framework:

/*! knockout-spa (https://github.com/onlyurei/knockout-spa) * Copyright 2015-2016 Cheng Fan * MIT Licensed (https://raw.githubusercontent.com/onlyurei/knockout-spa/master/LICENSE) */

define(['app/shared/root-bindings', 'framework/page-disposer', 'ko', 'sugar'], function (
  RootBindings, PageDisposer, ko) {

  var initialRun = true;

  var Page = {
    init: function (name, data, controller, path) {
      Page.loading(false);

      name = name.toLowerCase();

      if ((Page.page().name == name) && (Page.page().data == data)) { // if the requested page is the same page, immediately call controller without going further
        if (controller) {
          controller(data);
        }

        document.title = Page.title();

        if (Page.initExtra) {
          Page.initExtra(name, data, controller);
        }

        return data;
      }

      var autoDispose = (Page.page().data.dispose && Page.page().data.dispose(Page)) || true; // if the requested page is not the same page, dispose current page first before swap to the new page
      if (autoDispose !== false) {
        // auto-dispose page's exposed observables and primitive properties to initial values. if not desired, return
        // false in dispose function to suppress auto-disposal for all public properties of the page, or make the
        // particular properties private
        PageDisposer.dispose(Page.page().data);
      }

      PageDisposer.init(data); //store initial observable and primitive properties values of the page
      var initialized = (data.init && data.init(Page)) || true; // init view model and call controller (optional) before template is swapped-in
      if (initialized === false) {
        return false; // stop initialization if page's init function return false (access control, etc.)
      }
      if (controller) {
        controller(data);
      }

      Page.pageClass([name, ('ontouchstart' in document.documentElement) ? 'touch' : 'no-touch'].join(' '));
      Page.page({
        name: name,
        data: data,
        path: path
      }); // to test if template finished rendering, use afterRender binding in the template binding

      document.title = Page.title();

      if (Page.initExtra) {
        Page.initExtra(name, data, controller); // useful for common init tasks for all pages such as anaylitics page view tracking, can be set in RootBindings
      }

      if (initialRun) {
        ko.applyBindings(Page, document.getElementsByTagName('html')[0]); // apply binding at root node to be able to bind to anywhere
        initialRun = false;
      }

      return data;
    },
    page: ko.observable({
      name: '', // name of the page - auto-set by the framework, no need to worry
      data: {
        init: function () {}, // preparation before the page's template is rendered, such as checking access control, init/instantiate modules used by the page, etc.
        dispose: function () {} // properly dispose the page to prevent memory leaks and UI leftovers (important for SPA since page doesn't refresh between page views) - remove DOM element event listeners, dispose knockout manual subscriptions, etc.
      }
    }),
    pageClass: ko.observable(''),
    loading: ko.observable(false),
    title: function () {
      return Page.page().name.titleize(); // override in RootBindings as needed
    }
  };

  Object.merge(Page, RootBindings); // additional root bindings as needed by the app

  return Page;

});

A mini but full-fledged SPA framework built on top of Knockout, Require, Director, jQuery, Sugar. https://github.com/onlyurei/knockout-spa

Live Demo: https://knockout-spa.mybluemix.net


Need Your Help

Email response in java

java email

I am working in email response but unable to find any solution.I need to get response when email failure or success in Java.

Extract a file name out of a path found in an ini file

string batch-file

I need to extract information from a path found on a line in a batch file. Specifically the line says: