Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does KnockoutJS provide suitable architecture for building large web apps?

Quick question:

Will KnockoutJS provide a solid ground for developing a large web app? I am afraid of having one huge viewModel that will become unmaintainable.

Background info

I'll be building a web app that will be heavily client-side based. The backend will just be a RESTful endpoint. The entire interface of the web app will be built in pure HTML/CSS/JS - no server side scripting involved.

The web app itself will consist of several smaller apps with one general login (kind of like Google's web apps where you have Gmail, Docs, Calendar, Reader, etc.).

Each of those web apps will have some common functionality (such as a sidebar tree view, a top bar menu view, a notifications system), and some app-unique features. Usually I break my apps down to encapsulate functionality, something like:

var myNamespace = {     common: {         settings: {},         user: {},         notifications: {}     },     app1: {},     app2: {},     app3: {} }; 

Now, I really enjoy working with KnockoutJS and figured that it will be helpful when building some elements of my project (such as the notification system, or an advanced grid view with auto-refresh as the app will support collaboration). But I just can't figure out where to put my viewModel into this structure.

I can only find trivial examples of how to build apps with KnockoutJS. Can you actually build something more advanced than a Twitter reader with it? Are there any good examples of how to break down a lot of functionality in the viewModel, or perhaps into many viewModels?

Proposed solution

While the more theoretical question (the Quick question) is still kind of unanswered here, I think I've found a solution that works in practice. @Simon 's answer gave me some food for thought, and here's what I've got so far:

// First: a collection of Observables that I want to share ld.collectionOfObservables = {     notifications: ko.observableArray([]), };  // Now let's define a viewModel. I put all my stuff inside the // 'ld' namespace to avoid cluttering the global object.  ld.viewModel1 = function (args) {     // Look inside args and bind all given parameters      // Normally you will want args to be an object of Observables.      for (var key in args) {         if (args.hasOwnProperty(key)) {             this[key] = args[key];         }     };     // So, by now we already have some observables in     // 'this', if there were any supplied in 'args'.     // Additionally, we define some model-unique properties/observables     this.folders = [ 'Inbox', 'Archive', 'Sent', 'Spam' ];     this.selectedFolder = ko.observable('Inbox'); }; // *** Let's pretend I create similar class and call it ld.viewModel2 *** ld.viewModel2 = function (args) { .... }  // OK, now go on and instantiate our viewModels! // This is the fun part: we can provide 0-many observables here, by providing them in an object // This way we can share observables among viewModels by simply suppling the same observables to different viewModels var vm1 = new ld.viewModel1({      notifications: ld.collectionOfObservables.notifications,  // we take an Observable that was defined in the collection }); var vm2 = new ld.viewModel2({      notifications: ld.collectionOfObservables.notifications,  // shared with vm1 });  // Of course, we could just send the entire ld.collectionOfObservables as an array  // but I wanted to show that you can be more flexible and chose what to share. // Not easy to illustrate with *one* shared Observable - notifications -  // but I hope you get the point. :)  // Finally, initiate the new viewModels in a specified scope ko.applyBindings(vm1, document.getElementById('leftPane'));  ko.applyBindings(vm2, document.getElementById('bottomPane')); 

Now, if JS had real inheritance it'd be even better cause right now I feel that all my viewModels start with this:

for (var key in args) {     if (args.hasOwnProperty(key)) {         this[key] = args[key];     } }; 

But that's just a minor inconvenience. Let me know what you think!

Edit 1: Could the solution be as simple as using the with: binding? See "1. Control flow bindings" for an example.

Edit 2: I think my last edit was too quick. with: binding may help with the structure of your code, but AFAIK it doesn't help you share observables between those different parts. So the proposed solution above is still the way to go.

like image 606
Jacob Avatar asked Nov 01 '11 08:11

Jacob


People also ask

What is KnockoutJS used for?

KnockoutJS is basically a library written in JavaScript, based on MVVM pattern that helps developers build rich and responsive websites.

Where is knockout js used?

Knockout. js is a minimalist JavaScript framework for web application development. It is a JavaScript library that allows binding HTML elements against any data model. It is primarily used for creating rich and responsive display as well as editor user interfaces with a clean, underlying data model.

Which of the following architecture is implemented by knockout?

js Application Development. Knockout is a JavaScript library that uses a Model-View-View Model (MVVM) architecture that makes it easy for developers to create dynamic and interactive UI with a logical underlying data model.


1 Answers

You can use partial views and share observables between them.

    var some_observable = ko.observable()      var Model1 = function(something) {         this.something_1 = something;     };     var Model2 = function(something) {         this.something_2 = something;     };      var view_1 = Model1(some_observable);     var view_2 = Model2(some_observable);      ko.applyBindings(view_1, document.getElementById('some-id'));     ko.applyBindings(view_2, document.getElementById('some-other-id'));      <div id='some-id'>         <input data-bind='value: something_1' />     </div>     <div id='some-other-id'>         <input data-bind='value: something_2' />     </div> 

I've been using this aproach to maintain a list photos in a gallery application, where one view renders thumbnails and another view takes care of uploads.

like image 50
Simon Avatar answered Sep 16 '22 14:09

Simon