Knock Out - JS split - javascript

We developed a WEB based application using Knock out and Pager JS. We are almost to the end of the project. We have only one view model that serves the data binding for all data elements shown on UI screen. We are looking out for the options to split the JS files to make it more efficient and readable. Since we have only one view model that serves the whole data binding, its easier for us to call same methods for different actions using self.methodName();. My Questions are below,
1) If we are going to split up the View models into multiple files, how do we invoke a method from one view model to another view model.
2) I was checking abt the namespace to split the files using knockout, but not sure how far it works?
3) Some recommendation using require js, I seen some examples.. but not sure whether that will resolve the issue.
We are apply the databinding like below,
window.VM = new viewModel();
ko.applyBindings(window.VM);
4) If the content of the data is been shared with mutliple screens, how do we bind for each div.. for example, if I want to show the contact detail screen in Contact Detail and also subset of contact Detail information... How do we acheive it.. Based on my understanding, the databinding applies to a div element.. If I want to show the same data on two different screen, how we will acheive this...
Sorry for asking everything in one question..
Thanks,
Ramesh

Definitely you have to read about PubSub concept, which is easy implementable with KO.
E.g. http://www.knockmeout.net/2012/05/using-ko-native-pubsub.html

Related

Angular JS cascade notifications

I need your advice to help me.
I'm making an Angular JS app and I need some notifications like angular-toastr or angular-ui-notification but showing not like a list but cascade. Like in picture bellow.
Can anybody help with advice or realization such kind of notifications?
So I think what you want to do is divide and conquer this problem:
Think about the UI as a set of components. For the picture above, you might have the following.
// Notification Cascacder applies DOM transformations to a list of
<notification-cascader>
// Iterates over a list of notifications
<notification-list>
// Contains primary DOM for a notification
// accepts a variety of arguments for opacity, notification-message, etc.
<notification-card> </notification-card>
</notification-list>
</notification-cascader>
Now that you've broken it up you can determine what the API for each component may be, write the tests and then code the component. Writing it in this way will increase the reusability of each of the angular components. You could use a single notification-card without its parent in parts of the application. Although it isn't angularjs related you can read this and apply the concepts
https://reactjs.org/docs/thinking-in-react.html

Can event-handling be removed from KnockoutJS models and views?

I've been using KnockoutJS for some time now, mainly on small-to-medium sized projects. However, I'm now working on a very large project with many different views of the same data. For example, a product may be displayed to the customer, allowing them to add products to their shopping cart, and also to an administrator, allowing them to edit the product name, price and available stock. I want to be able to use the same model in both cases, but designing a solution with KnockoutJS is proving difficult. Specifically, I am having two issues:
I want to be able to re-use certain "view" functionality without repeating myself. For example, in both the customer- and administrator- view of products, clicking the product thumbnail displays the product image in fullscreen. Instead of each view containing the same verbose binding code (e.g., <img data-bind="event:{click:function codeToZoom(){}}"/> in both views), I can move the binding information to the model itself. So the above becomes <img data-bind="event:imageEvents()"/>. However, doing the above forces me to include code that responds to user input in my model, which violates the single-responsibility principle - e.g., the model is reponsible for business logic, not responding to user input. If I decided I wanted an administrator clicking the thumbnail to open an "Upload New Image" dialog, then I'd need to implement a imageEventsForAdministrator() function.
I've asked people how they deal with the above, and their answer has been "Write two different models." This sounds good until you realise that a product has a lot of embedded logic, and writing two different models forces you to duplicate that logic. So:
According to KnockoutJS, what is the recommended approach for separating business logic from responding to events/user-input?
Your post is interesting and understandable... yet really rather broad for Stack Overflow.
To answer some of your more specific subquestions though:
I want to be able to re-use certain "view" functionality without repeating myself.
There are two typical constructs for tackling this issue:
Use templates to do so. Knockout will keep the template as a "prototype" view, and instantiate new instances (and clean up) as needed.
Load view html dynamically as "partial views" if you will, and use the appropriate applyBindings overload to render those bits only when needed.
For example, [...] clicking the product thumbnail displays the product image in fullscreen [...] <img data-bind="event:{click:function codeToZoom(){}}"/> in both views
Well, there's several options here. I find that if you want you can actually de-duplicate code as much as theoretically possible. First, you can usually do this:
<img data-bind="event:{click: myHandler}"/>
And you can use some kind of prototypical or classical inheritance on your view models to make sure myHandler is only defined once.
Again, if you find yourself repeating the <img... bit: use KO templates.
Moving on:
This sounds good until you realise that a product has a lot of embedded logic, and writing two different models forces you to duplicate that logic.
In that case you're probably violating the SRP. You probably need to take that logic out of your view models and place it somewhere else (e.g. in controllers, DALs, etc.). But that topic is really broad, our sister site has an entire tag dedicated to it.
Finally, you ask:
According to KnockoutJS, what is the recommended approach for separating business logic from responding to events/user-input?
KnockoutJS recommends no particular approach.
That is, KO is an MVVM library, and as such does nudge you in a certain direction, but it doesn't really force you to take any particular approach with this. It's really up to you to write and structure infrastructure and code for common business logic, think up a good inheritance strategy or something similar, etc.
So it's up to you.
As a footnote, if you haven't already, I'd recommend running through some AngularJS tutorials as well. It has MVVM style bindings, but it is IMO more opinionated about how to solve the problems you're facing. (This is not advice to switch; merely advice to find inspiration in KO-alternatives.)

Angular.js controllers

Note: Sorry for the length of the post, but the reason I decided not to break it down in separate questions was because I find these issues hard to address without a complex problem like this. I am dazzled, and a bit afraid, that I'm trying to force Angular to do stuff for me which is not the 'Angular way'. Any advice would be highly appreciated, and would probably get me on the right track with Angular.
My problem is as follows:
I have a dynamically generated form, controlled by myFormCtrl. I want to go extremely modular: I want to use it whenever and wherever. This means, that sometimes I'll need to put it somewhere as-is, sometimes I need to nest forms dynamically (like when I change a form value, and other sub-form appears), or control two separate forms as one in a view by a parent controller, with one 'Save' button for both. The myFormCtrl uses $scope.type_id and $scope.rowid to know, which record should it display from the database. The records are then Ajax-fetched by a service, and saved under the myFromCtrl's $scope.formItems. When saved, the form sends back data to the server (via service) with the type_id and scope credentials, so the restful api knows where to put the record.
In theory that would be really easy to do in Angular.js.
It definitely would be in every object-orientated language: The parent class could call a public method of getFormValues() of myFormCtrl. Now that can't be done in Angular: parent can't read children's scope.
For me, it seems, that this is not a simple 'how to communicate between controllers' issue. I know that the answer to that question is services, events, scope inheritance.
Also, a number of other problems seem to emerge from each solution I found sofar.
So I have a myFormCtrlBase class, which does basic stuff, and other more advanced classes extend this one. I also have a formControls.html, and a formLayout.html partial. The first contains an ng-switch, and gives the appropriate input element based on $scope.formItem.controltype, the second has the html layout of a common form, ng-including formControls.html at the right places. It utilizes ng-repeat="formItem in formItems", so that's where formControls.html's $scope.formItem comes from.
When I want the form to have a different layout for example, I create a customFormLayout.html partial ng-controlled by the myFormCtrl class.
First question: what if my form layout can't be put in an ng-repeat?
Like when form elements need to be placed scattered across the page, or form layout is not something which could be fit in an ng-repeat loop. my formControls.html still expects a $scope.formItem to work with. Easy OO solution: parent puts formItem in child's scope.
My solution: I created a <formItemScopeChanger formItemScope="formItems[1]"> directive which gets formItems[1] as an attribute, and turns it to $scope.formItem variable. This solutions feels messy: directives are not meant to be used like this. Doesn't seem very Angulary. Is this really the best solution?
Second question: Is ng-init really that evil?
Say, form is not put in the view by $routeProvider, but in a custom partial: rent-a-car.html. Here, I want to have a form where the user can select a car, and an other form, where I get his contacts. The two forms work with different $scope.type_id's, so there need to be two different forms:
<h1>Rent a car!</h1>
<div ng-controller="myFormCtrl" ng-init="type_id='rentOrder'">
<div ng-include="'formLayout.html'"></div>
</div>
<h2>Your contact information</h2>
<div ng-controller="myFormCtrl" ng-init="type_id='User';rowid='{{userData.rowid}}'">
<div ng-include="'formLayout.html'"></div>
</div>
Angular docs sais, that the only appropriate use of ng-init is when aliasing ng-repeat values. I don't see what the problem is with the example above - it is still the cleanest solution, isn't it?
I use the same technique with nested forms - I put a controller in with a template, initialized from the html by ng-init, and shown/hidden with an ng-if condition.
BTW, this is the only real initialization technique I found beside writing a new controllers (extending myFormCtrlBase). In an OO language, parent would write into the child's scope and then initialize it.
Perhaps my approach is influenced by my previously used languages and programming techniques, and is absolutely wrong.
Some would say, 'get init values from parent scopes!', but I can't seem to understand how that would be safe and efficient. I'd need to do $scope.type_id=($scope.type_id || $routeParams.type_id) with every scope property, which is first: really not nice to look at, second: is risky. Maybe this is a single form in a simple template, but somewhere in the scope hierarchy, there is a possibility, that it will find a completely different type_id. Perhaps it will be a completely different controller's type_id.
I don't see how using '.'-s in my scope variables would help. I has the same risk as I see it.
Third question: how to handle rentACar.html submission?
When hitting a Save button on my rentACar.html page, the rentACarCtrl (the controller in charge of the model of the view) should somehow retrieve the values of the two forms, and handle the validation and submission. I can't seem to understand how the common mantra 'controllers communicate through services' would be applicable here. A service for only to these two forms?
Am I on the right track? Every one of these solutions seem quirky. I feel lost :)
+ 1 question: Even after all this hassle, I can't seem to find a good reason why Angular wouldn't let parents call children's public stuff. Is there a good reason? Most of the above problems would have an easy answer in every true OO js framework.
You need to think about how you would test the logic of each of these components. Ask yourself how each of these 'features' work in isolation.
A few tips to help get you back on track:
Try and say away from a 'base' controller, I have hit many dead ends with scope inheritance, the logic gets muddled and hard to follow. Also this affects testing, because you find yourself having to stand up more objects than should be necessary for a test
Favor a singleton (angular service) for shared state over scope inheritance (a parent controller)
Create a directive and bind to the shared services state before using ng-include (prefer interacting with a service over scope inheritance)
Use an event pattern when another service or controller needs to now about events triggered from directives. A shared service (state) can listen for those events
What your asking is quite complex and I would like to help, Try to focus on one feature at a time and provide some code, I can show you how to use a shared service and the event pattern once you provide some examples
Also, taking a test first approach will often reveal the best 'Angular Way' of doing things.
Thanks to Mark-Sullivan, and a lot of work, trial-and-error attempts, the whole thing has boiled down to this. I'd like to get feedback from Mark, and other Angular gurus about this. What do you think?
You don't do class/prototypical inheritance in Angular.js. It is hard to test, and thats a big problem. For those, who are looking for 'inheritance' in Angular, I recommend this:
Your base class is the controller. The controller is an abstract model anyways, so it is perfect for that purpose. Use a $scope.init() function in your controller, but don't call it from there!
If you want to 'extend' your controller's functionality, use directives. In you directive link() function, call the controller's $scope.init(). (when compiling, angular runs controllers first, and directive link functions after). If scope had a $scope.name='base', in the directive link you will be able to redefine $scope.name=child, and after that, run $scope.init().
But wait! But this only allows a single-level inheritance. - Yes, thats true. But if you are looking for multilevel inheritance, you should use Services.
Multilevel inheritance is nothing else, but sharing the same code in a hierarchical class structure. For this purpose, use Services, and throw in these services with the dependency injector into your directives. Soo easy. This should be easy to accomplish, easy to understand, and tests run smooth.
Directives are very powerful tools, because you can dynamically combine partials with controllers.

mvc approach with javascript / jquery no framework

I'm developing a large scale application. Initially my approach was confused , I am a beginner in javascript even if I develop since January.
I was looking for an mvc approach and I found some guide lines, like :
Model : contains AJAX call , and services
Controller: e.g. jQuery widget and so on
View: e.g. rendering of HTML and so on..
I don't really have clearly how to structure a javascript application following perfectly the three above suggestions. I can do everything, I can manage template I can write jQuery manipulation , I can do AJAX call.
What is not clear to me is how to get really divided these three modules. When I try this approach I'm not able to make any module to do only what it has to do.
I tried also an MV* approach which, for what I see and for my needs maybe it's a better approach, because I have to do bind tons of divs , generate events , all by client side, receiving only data from server side.
What I would like to know:
Which are the really competences of each Module?
If, for example, I have to bind a click event to a button , where do I have to write the
.on('click',callback)
method? Where I have to write the callback he's gonna call?
I wrote : no framework because I'm sure that if I don't understand an approach writing it from scratch, its impossibile I will completely understand the use of a complete framework.
I hope that my doubts were clear, if not, please comment, I'll try to explain better if I can.
Sorry for my english in any case.
This is not an answer because there is no one answer. I just want to mention a few do's and don't's.
Do store pure data in the model. Think of it as business objects rather than display objects. For example, money should be stored in the model as a number, probably with some digits after the decimal point, plus an indicator of what currency it is, if that matters. Don't store the number as a string with local choices of the characters to separate the 1000's and the integer part from the fractional part and the right number of digits after the decimal point.
Do put the handler code for the click events (and similar user actions) in the controller.
Do put the code that causes updates the screen on load or on any external event in the controller. (An external event might be something like an update to a stock price due to stock exchange data or an update to the weather report coming into the application.)
Do put the HTML or the code that generates HTML as part of the view.
Do have the controller call the view to get the display updated/changed at the right times.
Do have either the controller or the view call the model to get the current model data values or the update the the current model data. (See similar "don't" below.)
Do reduce the connectivity between the three parts--M, V and C. Define clearly who can talk to whom for what purpose and keep that rule sacred. If you find an exception, its a smell indicating a problem with the big picture of those rules.
And some more things
Don't put the code that displays the screen on load in the controller. That's clearly a view concern. This means the controller has to call into the view somehow.
Don't spaghetti connect the M, V and C code in random fashions. For example, you might make a rule that the model never calls code in the view or controller.
Don't have both the controller and the view talking to the model.
Questions:
Where does the code go that hooks up the event handlers?
Where do you put the "business logic"? This is the code that knows the rules of your application. Validation, for example, is business logic. Some code may need to know how zip codes look for the US and postal codes for the UK or Canada. If the validation fails, the controller is the one that tells the view to show an error message or red mark or vibrating box or whatever. Does the business logic of validation rules also go in the controller?
Where does the code go that loads data from external data sources? (servers, JSON web services, databases, screen scraping, etc.) You might think "model" but then the model has to call into the controller when new data comes back to tell it to update the view. That doesn't seem right.
Similarly, what is the code that handles the equivalent of a "submit" button, moving to another screen.
If converting data from a form that is displayable on the screen to a form that is pure data is too slow, what do you do?
There are always self-contained portions of the screen that can be built with their own MV&C. How do you set up interactions between multiples of those little MVCs and the big MVC that is the whole screen? Are those little guys the views for the big MVC? Or are the controllers? Can they be both at once? Is there a big model with the little models in it or does data flow between little models and big models? Who knows about all this?
Is there an even bigger MVC comprised of multiple screens? It would probably be on the server if it exists.
How do you handle "synthetic" events? This is something like an "event" that occurs when the data was ok but is now in a bad state (or was incomplete and is now complete). Listeners to this event can disable the "Submit" button and display error messages or animations calling the user attention to the problem. It could be anything that isn't a generic event built into the framework or language. Perhaps its a message to the server indicating a change in the state of a multiplayer game's world view.
This is just a list of things that pop to mind when you are writing your own MVC or when evaluating an existing framework.
There is no clear answer outside a specific framework. Although the general responsibilities of the MVC pattern are (almost) clear to everyone, each framework has its own interpretation of exactly what pieces of code to put in each of these layers - some frameworks even skip some layers, or add different ones instead.
I know you don't want to use a framework, but still, it's worth to have an overview of how the current solutions work, so you can make an informed decision if you like the way they work or if you prefer to roll your own.
I recommend you at least take a look at one server side MVC framework (such as Ruby on Rails or Asp.Net MVC) and some client side MVC frameworks too (Backbone.js, Angular.js, etc. - javascript only). Read their documentations, and learn from the choices others have made (and tested). The site todo mvc can help you to compare different client MVC frameworks to find the approach you like better.
This is not a simple topic, and discussing the pros and cons of each approach from scratch can take forever.

How to make a single page app with knockout.js?

How do you organize the view-model classes? Separate classes or one giant one (and how to modularize the giant one)? How to switch between 'pages' (with data loaded with ajax of course)? How to load templates for backbonejs after page load? Examples and tutorials would be appreciated as long as they are more advanced that he ones on their site.
Wow, lots of questions all rolled into one. I'll try to hit them here, but a disclaimer that I am writing an entire course for Pluralsight on Knockout ... so i can't go into the depth you need an a comment box :)
1) How do you organize model-view classes?
I think you mean view-model classes. I recommend creating a view model that contains all of the properties and methods that the page requires. Put the view model in an enclosure and keep all of that javascript in its own file. For example, if you have page customers.html for your structure, you could have customers.js for with your view model.
2) Separate classes or one giant one (and how to modularize the giant one)?
Each view model is in its own file. Generally 1 view model per js file (but you could certainly put interrelated ones int he same file). Also, generally 1 view model per view (but again, you can go beyond this in some cases).
For Models you can create them all in a single models file if you like, or put them in separate files. For smaller apps I like 1 models.js files since most models are pretty straight forward, small, and contain simple properties (albeit observables). But here, it really is a matter of choice.
3) How to switch between pages?
The mechanism is not specific to Knockout, so you can use links or even custom controls (menus, tabs, etc). Your call. Once you decide how to navigate to a different page, I assume you need to pass data between the 2 for context One way to do this is in the querystring with an ID, another way is local storage (for larger items you need to store in the client), or there are other options too. Again, it really depends on what you need to pass between the pages. A lot of times I design the pages to be self sufficient so I dont need to pass much between them. For what I need to pass, i try to send as little as I can and look up data based on keys (in ajax calls or local storage ... wherever the data lives).
I hope this helps a bit.
UPDATE: Here is the link I mentioned to my Knockout.js course on Pluralsight

Categories

Resources