knockout.jssingle-page-applicationsammy.js

Knockoutjs Single Page Application binding issues


Hello so I'm working on an .Net single page application using Knockoutjs, Sammy.js, and Rest Web API. I'm somewhat new to these libraries and I've run into a few core design issues and I'm hoping to gain some insight.

The main issue I have is using knockouts ko.applybinding targeted at specific elements.

this.get("#/Classroom", function(context) {
    dataPack.build(PageLoc, context)
    appPres.reload();
    ko.applyBindings(new classroomVmCore.View(), document.getElementById('view-Classroom'));

});

Since this is a single page application I have to dynamically append my views. The dataPack.build is what grabs my view and binds to the context of the single page. That functionality works fine as expected, but when it comes to ko.applyBindings I find the following issues occur..

  1. Any page refresh loses my view model and if the sammy.js hash isn't hit the data is missing. This problem mainly occurs for any shared content (ex. navigation items, layout items, etc) Since this data has its own view model when I hit the #/Classroom hash again those shared models are lost.

  2. Is their another option besides using the constructor function below for my view model? Setting that to a variable and then trying to adjust or add to that variable doesn't seem to adjust my model.

I'm essentially looking for a way to update/refresh my model at any time so I can handle a page fresh.

Has anyone used these libraries for an SPA run into these issues? How did you structure your views and bindings?

Any help or ideas are greatly appreciated.


Solution

  • I've created my own site (not plugging here, see profile if you desire) as a SPA with knockout. I actually use templates to achieve my goal. This is a shortend example of how I do it.

    Sorry, I've never used sammy.js to have anything to say about that.

    function MainVM() {
      var self = this;
    
      self.ContactVM = ko.observable(new AboutMeVM('John', 'code'))
    
      self.Content = ko.observable({
        name: 'HomeTemplate'
      });
    
      self.ShowHome = function() {
        // Page using MainVM
        self.Content({
          name: 'HomeTemplate'
        });
      }
    
      self.ShowContact = function() {
        // Page with on demand VM
        self.Content({
          name: 'ContactTemplate',
          data: new ContactVM('me', "555-5555")
        })
      }
    
      self.ShowContactSteve = function() {
        // Page with on demand VM
        self.Content({
          name: 'ContactTemplate',
          data: new ContactVM('Steve', "555-1234")
        })
      }
    
      self.ShowAboutMe = function() {
        // Page with a static VM
        self.Content({
          name: 'AboutMeTemplate',
          data: self.ContactVM
        });
      }
    }
    
    
    
    function ContactVM(name, number) {
      var self = this;
      self.Name = ko.observable(name);
      self.Phone = ko.observable(number);
    }
    
    function AboutMeVM(name, job) {
      var self = this;
      self.Name = ko.observable(name);
      self.Job = ko.observable(job);
    }
    
    ko.applyBindings(new MainVM());
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <script type="text/html" id="AboutMeTemplate">
      About me:<br> i am <span data-bind="text: Name"></span> and I <span data-bind="text: Job"></span>
    </script>
    
    <script type="text/html" id="ContactTemplate">
      Contact <span data-bind="text: Name"></span>: <span data-bind="text: Phone"></span>
    </script>
    
    <script type="text/html" id="HomeTemplate">
      Welcome to my website
    </script>
    
    <div>
      <h3>Links</h3>
      <a data-bind="click: ShowHome">Home</a> <br>
      <a data-bind="click: ShowContact">Contact Me</a><br>
      <a data-bind="click: ShowContactSteve">Contact Steve</a><br>
      <a data-bind="click: ShowAboutMe">About Me</a><br>
      <hr>
      <h3> Page content</h3>
      <div data-bind="template: Content"></div>
    </div>