Use KnockoutJS Modules in AngularJS
Posted By : Rajan Rawat | 11-Apr-2017
Using KnockoutJS View Model in an AngularJS App
Angular 1.3 has a ngModelOptions directive that gives you the some flexibility in the way ngModel does in the databinding. The new and the interesting option is getterSetter, that allows the angular model is actually a getter/setter function
Before we start and get into the angular over a year ago, i does the frontend framework with knockout. But the knockoutJs models view having the observables, observables array and computeds, they all are implemented as getter/setter. But when i saw angular has added a support for binding the getter/setter. Then i realise i should do this and see i can use knockoutJS modules in AngularJS
So the question is can we use knockout view model without modifications in angularjs app and the answers is yes and i am pretty sure if there is any real-world uses, it will be definitely and interesting exercise
So lets began with a demo of shopping cart. Its a shopping cart which have observables, observables arrays and computeds
ther are cart and cartline view models from knockout app and we will reuse in angular app
function formatCurrency(value)
return "$" + value.toFixed(2);
}
var shoppingcartLine = function() {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
self.category.subscribe(function() {
self.product(undefined);
});
};
var shoppingcart = function() {
var self = this;
self.list = ko.observableArray([new shoppingcartLine()]);
self.grandTotal = ko.computed(function() {
var total = 0;
$.each(self.list(), function() { total += this.subtotal() })
return total;
});
self.addLine = function() { self.list.push(new shoppingcartLine()) };
self.removeLine = function(line) { self.list.remove(line) };
self.save = function() {
var dataToSave = $.map(self.list(), function(line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
};
Now if we want use Angular here we have to create module and controller . The controller have to be simpler, all we have to do is new up the Shoppingcart View Model and list of the products will be same as in the knockout demo app.
angular.module('Shoppingcart', [])
.controller('ShoppingCartController', CartController);function CartController() {
this.cart = new ShoppingCart();
this.sampleProductCategories = sampleProductCategories;
}
Now the original shopping cart with knockout Bindings
<tbody data-bind='foreach: list'>
<tr>
<td>
<select data-bind='options: sampleProductCategories, optionsText: "name", optionsCaption: "Select...", value: category'> </select>
</td>
<td data-bind="with: category">
<select data-bind='options: products, optionsText: "name", optionsCaption: "Select...", value: $parent.product'> </select>
</td>
<td class='price' data-bind='with: product'>
<span data-bind='text: formatCurrency(price)'> </span>
</td>
<td class='quantity'>
<input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"' />
</td>
<td class='price'>
<span data-bind='visible: product, text: formatCurrency(subtotal())' > </span>
</td>
<td>
<a href='#' data-bind='click: $parent.removeLine'>Remove</a>
</td>
</tr>
</tbody>
Now when we change it into the Angular
<tbody>
<tr ng-repeat="line in vm.shoppingcart.lines()">
<td>
<select ng-options="category.name for category in vm.sampleProductCategories"
ng-model="line.category" ng-model-options="{ getterSetter: true }">
<option value="">Select...</option>
</select>
</td>
<td>
<select ng-options="product.name for product in line.category().products"
ng-model="line.product" ng-model-options="{ getterSetter: true }"
ng-show="line.category()">
<option value="">Select...</option>
</select>
</td>
<td class='price'>
<span ng-bind='line.product().price | currency'></span>
</td>
<td class='quantity'>
<input ng-show="line.product()" ng-model="line.quantity" ng-model-options="{ getterSetter: true }" />
</td>
<td class='price'>
<span ng-show="line.product()" ng-bind="line.subtotal() | currency"></span>
</td>
<td>
<a href='#' ng-click="vm.cart.removeLine(line)">Remove</a>
</td>
</tr>
</tbody>
Knockout binding | Angular equivalent |
foreach | ng-repeat |
options | ng-options |
value | ng-model with getterSetter:true |
visible | ng-show |
formatCurrency (custom fn) | currency filter (built-in) |
click | ng-click |
So the now the new Angularjs app works exactly like the KnocoutJS App. If you want see the more complex view Model which make rest API calls for examples. So definitely you have to do extra work to make sure Angular digest cycle is triggered properly.
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
Rajan Rawat
Rajan is a UI Developer, having good knowledge of HTML, CSS and javascript. His hobbies are internet surfing and watching sports.