Apply filter on knockout reduce function - asp.net-mvc

I have below code in my razor view to populate radio button,
<!-- ko foreach: { data: ko.unwrap(cars).reduce(function (res, v, i) { res[i%2].push(v); return res; }, [[],[]]), as: 'cars' } -->
<div data-bind="foreach: cars">
<label class="car">
<div>
<input type="radio" name="Carinfo.Name" data-bind="checked: $root.carId, checkedValue: Id, value: Id"><span data-bind="text: model"></span
</div>
</label>
</div>
<!-- /ko -->
Trying to understand what reduce function is doing here
ko.unwrap(cars).reduce(function (res, v, i) { res[i%2].push(v); return res; }
Can I filter cars observable array (like v.Make == 'Honda'), inside reduce function and returned filtered cars to the DOM to populate radio button

First, you want to remove all this logic from the view and move it to a viewModel.
This will give you
proper intellisense (auto complete, hovering functions gives info on them and all these IDE goodness).
readability: you view will just look like that:
<!-- ko foreach: { data: filteredCars -->
Testability. You will be able to write unit tests on that view model property. While testing the view is particularly hard.
Now your answer:
Trying to understand what reduce function is doing here
ko.unwrap(cars).reduce(function (res, v, i) { res[i%2].push(v); return
res; }
ko.unwrap is a function which fetches the actual value of on object, no matter if it's observable or not. For example:
console.log(ko.unwrap(ko.observableArray([1, 2, 3])));
console.log(ko.unwrap([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
array reduce runs a callback against an array, and reduces all values inside an accumulator. To understand what this example is doing, let's run it on an easier example:
var cars = ["honda", "renault", "ford", "toyota", "volkswagen", "chevrolet", "volvo"];
var splitted = cars.reduce(function (res, v, i) {
res[i%2].push(v); return res;
}, [[],[]]);
console.log(splitted);
It's basically splitting your array of cars into two arrays. First array with cars having even indexes, and second with odd indexes.
Can I filter cars observable array (like v.Make == 'Honda'), inside
reduce function and returned filtered cars to the DOM to populate
radio button
Yes you can: again, a simple fiddle:
// let's say this observable comes from another VM
var cars = ko.observableArray([{
maker: "honda",
country: "japan"
}, {
maker: "renault",
country: "france"
}, {
maker: "ford",
country: "us"
}, {
maker: "toyota",
country: "japan"
}, {
maker: "volkswagen",
country: "germany"
}, {
maker: "chevrolet",
country: "us"
}, {
make: "volvo",
country: "sweden"
}]);
var viewModel = function() {
this.japaneseCars = ko.computed(function() {
return ko.unwrap(cars).reduce(function(result, v, i) {
if (v.country === "japan") {
result.push(v.maker);
}
return result;
}, []);
}, this);
};
var vm = new viewModel();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="foreach: japaneseCars">
<input type="radio" name="cars" data-bind="attr: { value: $data }">
<span data-bind=" text: $data " />
<br />
</div>

Related

Knockoutjs Multiselect shows index instead of text value when using viewbag

I'm using a viewbag to load the options for a multi-select list. However, when I do that I'm getting a 1-based index instead of the actual text value.
<td> #Html.DropDownList("MAMUserGroupName", (MultiSelectList)ViewBag.MAMUserGroupsList, new { multiple = "multiple", data_bind = "selectedOptions:MAMUserGroups" })</td>
Here's the viewModel:
var viewModel = new UserModel([
{
id: ko.observable(""), firstName: ko.observable(""), lastName: ko.observable(""),MAMUserGroups: ko.observable()
}
]);
When the value is selected and I call the knockout save function, the value is 1, 2, and/or 3, instead of the actual text value; in this case "Group1", "Group2", "Group3"
When I do it the standard way of hard-coded options like here it works as expected: Knockout selectedOptions example. But in my case I need to load it from the viewbag.
The #Html.DropdownList is a server side rendering of the list and knockoutjs is a client side rendering of the list and the two do not know about each other. What you need to do is either render the list to a javascript array on they page, or retrieve it via Ajax/fetch from the server then render it client side. So using your code examples, i would be filling you knockoutjs view model with the data you need. something like the following.
var PageModel = function(data) {
var users = ko.observableArray();
var userGroups = ko.observableArray();
var mappedUsers = data.Users.map(function(user) {
return {
id: ko.observable(user.id),
firstName: ko.observable(user.firstName),
lastName: ko.observable(user.lastName),
mameUserGroups: ko.observableArray()
};
});
users(mappedUsers);
var mappedGroups = data.MAMUserGroups.map(function(item) {
return {
id: item.id,
name: item.name
};
});
userGroups(mappedGroups);
return {
users: users,
userGroups: userGroups
};
};
ko.applyBindings(new PageModel({
//****** Data loaded here ******
Users: [{
id: 1,
firstName: "test",
lastName: "user 1"
}, {
id: 2,
firstName: "test",
lastName: "user 2"
}, {
id: 3,
firstName: "test",
lastName: "user 3"
}, {
id: 4,
firstName: "test",
lastName: "user 4"
}],
MAMUserGroups: [{
id: 1,
name: "User Group 1"
}, {
id: 2,
name: "User Group 2"
}, {
id: 3,
name: "User Group 3"
}, {
id: 4,
name: "User Group 4"
}]
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
<tbody data-bind="foreach: users">
<tr>
<td data-bind="text: firstName"></td>
<td data-bind="text: lastName"></td>
<td>
<select data-bind="options: $parent.userGroups, selectedOptions: mameUserGroups, optionsText: 'name' " size='5' multiple='true'> </select>
</td>
</tr>
</tbody>
</table>
<ul data-bind="foreach: users">
<li>
<span data-bind="text: firstName"></span><span data-bind="text: lastName"></span>
<ul data-bind="foreach: mameUserGroups">
<li data-bind="text: name"></li>
</ul>
</li>
</ul>
<!--
<script type="text/javascript">
// Render the data on the page server side to then be used client side
$().ready(function(){
var users = #(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Users)));
var mamUserGroups = #(Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.mamUserGroups)));
});
</script>
-->
EDIT Ajax implementation
This is one way to do it. probably more code than is needed but i like to break things up into separate area of responsibility. If you try running this snippet from here what you will get is an error alert and a finished alert for the users and user groups.
var app = window.app || {};
app.modelMap = (function() {
function userMap(user) {
return {
id: ko.observable(user.id),
firstName: ko.observable(user.firstName),
lastName: ko.observable(user.lastName),
mameUserGroups: ko.observableArray()
};
}
function userGroupMap(userGroup) {
return {
id: userGroup.id,
name: userGroup.name
};
}
return {
userMap: userMap,
userGroupMap: userGroupMap
}
})();
app.data = (function() {
function getUserGroups() {
return $.get("<MAMUSerGroup_URL_HERE>").then(function(data) {
alert("successfully retrieved user group data");
return data.map(app.modelMap.userGroupMap);
})
.fail(function() {
alert("error");
})
.always(function() {
alert("finished");
});
};
function getUsers() {
return $.get("<Users_URL_HERE>").then(function(data) {
alert("successfully retrieved user data");
return data.map(app.modelMap.userMap);
})
.fail(function() {
alert("error");
})
.always(function() {
alert("finished");
});
}
return {
getUserGroups: getUserGroups,
getUsers: getUsers
}
})();
app.pageModel = (function() {
var users = ko.observableArray();
var userGroups = ko.observableArray();
function getUsers() {
return app.data.getUsers().done(users);
}
function getUserGroups() {
return app.data.getUserGroups().done(userGroups);
}
function activate() {
getUsers();
getUserGroups();
}
var vm = {
users: users,
userGroups: userGroups,
activate: activate
};
return vm;
})();
var vm = app.pageModel;
vm.activate();
ko.applyBindings(vm);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

Load tabs with Ajax

I have a bootstrap nav-tab and I want to display dynamically content when I select a tab. Each tab must display a div with some text that is returned from ajax call at the controller's action GetSection().
<div class="tabbable">
<ul class="nav nav-tabs" data-bind="foreach: sections">
<li data-bind="css: { active: isSelected }">
<a href="#" data-bind="click: $parent.selectedSection">
<span data-bind="text: name" />
</a>
</li>
</ul>
<div class="tab-content" data-bind="foreach: sections">
<div class="tab-pane" data-bind="css: { active: isSelected }">
<span data-bind="text: 'In section: ' + retValue" />
</div>
</div>
</div>
Javascript code:
var Section = function (name, selected) {
this.name = name;
this.retValue = "";
this.isSelected = ko.computed(function () {
return this === selected();
}, this);
}
var ViewModel = function () {
var self = this;
self.selectedSection = ko.observable();
self.sections = ko.observableArray([
new Section('Tab One', self.selectedSection),
new Section('Tab Two', self.selectedSection),
new Section('Tab Three', self.selectedSection)
]);
self.selectedSection(self.sections()[0]);
self.selectedSection.subscribe(function () {
$.ajax({
url: '#Url.Action("GetSection")',
data: { name: self.selectedSection().name },
type: 'GET',
success: function (data) {
self.selectedSection().retValue=data.text;
}
});
});
}
ko.applyBindings(new ViewModel());
The problem is that retValue from ajax is not displayed. The controller action is this:
public JsonResult GetSection(string name)
{
var ret = new { text = name + "abcd" };
return Json(ret, JsonRequestBehavior.AllowGet);
}
Knockout can only know to update the view for properties that are obsverable (hence the name), so you need to make retValue observable:
var Section = function (name, selected) {
this.name = name; // <-- consider similar change here too
this.retValue = ko.observable(""); // <-- change here
this.isSelected = ko.computed(function () {
return this === selected();
}, this);
}
Then, you need to remember to set an obsverable's value by calling it as a method with the new value as its only argument, e.g.:
$.ajax({
url: '#Url.Action("GetSection")',
data: { name: self.selectedSection().name },
type: 'GET',
success: function (data) {
self.selectedSection().retValue(data.text); // <-- change here
}
});
And finally, if you're binding to a complex expression in your view you need to invoke it as a function (with no arguments) to get its value:
<span data-bind="text: 'In section: ' + retValue()" />
As a side note, realize that you can leave off the parentheses (consider it syntactic sugar from knockout) if you bind straight to just the observable, e.g.:
<span data-bind="text: retValue" />
Which is effectively equivalent to:
<span data-bind="text: retValue()" />
On a foot note, I see you've used this syntax for a click binding:
...
This works... but only by coincidence. You should realize these things together:
$parent.selectedSection contains the result of ko.observable() which means it is in fact a function that can be invoked
the click data-binding will invoke the expression it gets as a function, passing the contextual data (in your case a Section) to that function
So bascially, when the click happens, this happens:
$parent.selectedSection($data) // where $data == the current Section
Which effectively selects the Section.
It would be more verbose though a lot clearer if the $parent had a function:
var self = this;
self.selectChild = function(section) {
// Possibly handle other things here too, e.g. clean-up of the old selected tab
self.selectedSection(section);
}
And then use the click binding in this clear way:
...
On click the selectChild method will be called, again with the contextual data as the argument.
Instead of this
self.selectedSection().retValue=data.text;
Do this
self.selectedSection(data);

give default value to md-autocomplete

How to pass default value in md-autocomplete?
Image 1 : HTML code
Image 2 : JS code
Image 3 : Output
As you can see, I am not getting any default country as output. Is there any way to do that?
Assign yr SearchText the default value & selectedItem the object.
$scope.local ={
...
searchText : 'Default Value',
selectedItem : 'Default object'
...
}
I write small codepen with autocomplete and default value.
What you must do:
Init main model.
Define model field, used in autocomplete md-selected-item property.
Define callback for loading autocomplete items.
Before save main model extract id (or other field) from associated field.
Main error in your code here:
$scope.local = {
...
selectedItem: 1, // Must be object, but not integer
...
}
(function(A) {
"use strict";
var app = A.module('app', ['ngMaterial']);
function main(
$q,
$scope,
$timeout
) {
$timeout(function() {
$scope.user = {
firstname: "Maxim",
lastname: "Dunaevsky",
group: {
id: 1,
title: "Administrator"
}
};
}, 500);
$scope.loadGroups = function(filterText) {
var d = $q.defer(),
allItems = [{
id: 1,
title: 'Administrator'
}, {
id: 2,
title: 'Manager'
}, {
id: 3,
title: 'Moderator'
}, {
id: 4,
title: 'VIP-User'
}, {
id: 5,
title: 'Standard user'
}];
$timeout(function() {
var items = [];
A.forEach(allItems, function(item) {
if (item.title.indexOf(filterText) > -1) {
items.push(item);
}
});
d.resolve(items);
}, 1000);
return d.promise;
};
}
main.$inject = [
'$q',
'$scope',
'$timeout'
];
app.controller('Main', main);
}(this.angular));
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.js"></script>
</head>
<body ng-app="app" flex layout="column" layout-margin ng-controller="Main">
<md-content layout="column" class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Form</h3>
</div>
</md-toolbar>
<md-content class="md-whiteframe-z1">
<div class="md-padding">
<md-input-container>
<label for="firstname">First name</label>
<input type="text" name="firstname" ng-model="user.firstname" />
</md-input-container>
<md-input-container>
<label for="lastname">Last name</label>
<input type="text" name="lastname" ng-model="user.lastname" />
</md-input-container>
<md-autocomplete md-selected-item="user.group" md-items="item in loadGroups(filterText)" md-item-text="item.title" md-search-text="filterText">
<md-item-template>{{ item.title }}</md-item-template>
<md-not-found>No items.</md-not-found>
</md-autocomplete>
</div>
</md-content>
</md-content>
<md-content class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Model as JSON</h3>
</div>
</md-toolbar>
<md-content class="md-padding">
<p>
{{ user | json }}
</p>
</md-content>
</md-content>
</body>
I know this is an old question, but some people may benefit from my solution. I struggled with the problem of the model for the auto-complete being asynchronous and having my autocompletes as part of an ng-repeat. Many of the solutions to this problem found on the web have only a single auto complete and static data.
My solution was to add another directive to the autocomplete with a watch on the variable that I want to set as default for the auto complete.
in my template:
<md-autocomplete initscope='{{quote["Scope"+i]}}' ng-repeat='i in [1,2,3,4,5,6,7,8]'
class='m-1'
md-selected-item="ScopeSelected"
md-clear-button="true"
md-dropdown-position="top"
md-search-text="pScopeSearch"
md-selected-item-change='selectPScope(item.label,i)'
md-items="item in scopePSearch(pScopeSearch,i)"
md-item-text="item.label"
placeholder="Plowing Scope {{i}}"
md-min-length="3"
md-menu-class="autocomplete-custom-template"
>
then in my module:
Details.directive('initscope', function () {
return function (scope, element, attrs) {
scope.$watch(function (){
return attrs.initscope;
}, function (value, oldValue) {
//console.log(attrs.initscope)
if(oldValue=="" && value!="" && !scope.initialized){
//console.log(attrs.initscope);
var item = {id:0, order:0,label:attrs.initscope?attrs.initscope:"" }
scope.ScopeSelected = item;
scope.initialized = true;
}
});
};
});
this checks for changes to the quote["Scope"+i] (because initially it would be null) and creates an initial selected item and sets the autocompletes' selected item to that object. Then it sets an initialized value to true so that this never happens again.
I used timeout to do this.
$timeout(function() {
$scope.local = {selectedItem : 1}
}, 2000);

Kendo UI and knockout.js rowTemplate sorting

I have a MVC site where I use Kendo UI and knockout.js to display the pages. One scenario is to get the database information from server through $.getJSON and then display this information on a KendoUI grid.
<div data-bind="kendoGrid:{sortable:true, data:users, rowTemplate:'userRowTemplate'}>
<table>
<thead>
<tr>
<th>Username</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead> </table>
</div>
<script type="text/html">
<tr>
<td data-bind="text: Username"></td>
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<tr>
</script>
and the javascript :
<script type="text/javascript">
var ViewModel = function () {
var self=this;
self.users=ko.mapping.fromJS([]);
$getJSON("/UserManagementController/GetUsers",function(data){
ko.mapping.fromJS(data,{},self.users);
});
};
$(document).ready(function(){
var newViewModel=new ViewModel();
ko.applyBindings(newViewModel);
});
</script>
I want this data to be sortable on specific columns (the ones specified here are for example's sake), but I haven't been able to achieve this successfully. I have tried the solution from this knockout-kendo plugin issue post, which works well on simple objects, but does not work on observables. So my question is : how to map data from database through MVC controller to observables in knockout and displaying them in a Kendo grid, but still be able to sort them?
Thanks,
Alex Barac
You can do this by creating a JS view model to represent the data coming back from the server, and mapping the data into the view model. Then you can have simple objects that get set by subscribing to the matching observable properties to implement the sort.
Here is an example:
http://jsfiddle.net/R4Jys/1/
HTML:
<div data-bind="kendoGrid: gridOptions(myList)"></div>
<script id="rowTmpl" type="text/html">
<tr>
<td>
<span data-bind="text: firstName" />
</td>
<td>
<span data-bind="text: lastName" />
</td>
<td>
<span data-bind="text: userName" />
</td>
</tr>
</script>
JavaScript:
var gridItem = function () {
var self = this;
self.firstName = ko.observable();
self.firstNameSort;
self.firstName.subscribe(function (value) {
self.firstNameSort = value;
});
self.lastName = ko.observable();
self.lastNameSort;
self.lastName.subscribe(function (value) {
self.lastNameSort = value;
});
self.userName = ko.observable();
self.userNameSort;
self.userName.subscribe(function (value) {
self.userNameSort = value;
});
self.other = ko.observable('test');
return self;
};
var vm = function() {
var self = this;
self.myList = ko.observableArray();
self.test = ko.observable();
self.gridOptions = function (data) {
return {
data: data,
rowTemplate: 'rowTmpl',
useKOTemplates: true,
scrollable: true,
sortable: true,
columns: [
{
field: "firstNameSort",
title: "First Name",
width: 130
},
{
field: "lastNameSort",
title: "Last Name",
filterable: true
},
{
field: "userNameSort",
title: "Username"
}
]
}
};
var data = [{'firstName':'Steve', 'lastName':'Jones', 'userName': 'steve.jones'},
{'firstName':'Janet', 'lastName':'Smith', 'userName': 'janet.smith'},
{'firstName':'April', 'lastName':'Baker', 'userName': 'april.baker'},
{'firstName':'Dave', 'lastName':'Lee', 'userName': 'dave.lee'},
{'firstName':'Jack', 'lastName':'Bennet', 'userName': 'jack.bennet'},
{'firstName':'Chris', 'lastName':'Carter', 'userName': 'chris.carter'}];
self.myList(ko.utils.arrayMap(data, function(item) {
var g = new gridItem();
ko.mapping.fromJS(item, {}, g);
return g;
}));
};
var pageVm = new vm();
ko.applyBindings(pageVm);
As an alternative you can modify the kendo.web.js (version 2013.3.1119) on line 6844 & 6844.
Replace
compare: function(field) {
var selector = this.selector(field);
return function (a, b) {
a = selector(a);
b = selector(b);
With
compare: function(field) {
var selector = this.selector(field);
return function (a, b) {
a = ko.utils.unwrapObservable(selector(a));
b = ko.utils.unwrapObservable(selector(b));
By using the knockout utility "ko.utils.unwrapObservable" you can get the value of the observable for use when kendo compares the values of the column
DEFINE CUSTOM COMPARE FUNCTION will serves solution, where you can override the comparing function in field definition.
So you can do something like this:
$("#grid").kendoGrid({
dataSource: dataSource,
sortable: true,
columns: [{
field: "item",
sortable: {
compare: function(a, b) {
var valueA = a["item"];
var valueB = b["item"];
if (typeof valueA === "function") valueA = valueA();
if (typeof valueB === "function") valueB = valueB();
if (this.isNumeric(valueA) && this.isNumeric(valueB))
{
valueA = parseFloat(valueA);
valueB = parseFloat(valueB);
}
if (valueA && valueA.getTime && valueB && valueB.getTime)
{
valueA = valueA.getTime();
valueB = valueB.getTime();
}
if (valueA === valueB)
{
return a.__position - b.__position;
}
if (valueA == null)
{
return -1;
}
if (valueB == null)
{
return 1;
}
if (valueA.localeCompare)
{
return valueA.localeCompare(valueB);
}
return valueA > valueB ? 1 : -1;
}
}
}]
});
private isNumeric(input)
{
return (input - 0) == input && ('' + input).trim().length > 0;
}
The compare method is stolen from kendo script, but change is where the property is typeof function (what ko.observable is), it unwraps the value. Plus, I added support for numbers.

JQuery UI highlight effect color parameter ignored in Knockout foreach

Im trying to apply the JQuery UI highlight effect to an element when an item that is bound to a knockout observablearray is updated.
The highlight effect is applied but the highlight color used is always the elements current background color. even if I specify the highlight color using the { color: 'XXXXXXX' } option.
any ideas what might be happening?
Thanks,
Steve.
Code below: The element is the span.tag
<div class="row">
<div class="span12">
<div class="tagsinput favs span12" style="height: 100%;" data-bind="foreach: favs, visible: favs().length > 0">
<span class="tag" data-bind="css: $root.selectedFav() == userPrefID() ? 'selected-fav' : '', attr: { id: 'fav_' + userPrefID() }">
<span data-bind="text: name, click: $root.loadFav.bind($data)"></span>
<a class="tagsinput-fav-link"><i class="icon-trash" data-bind="click: $root.delFav.bind($data)"></i></a>
<a class="tagsinput-fav-link-two" data-bind="visible: $root.selectedFav() == userPrefID()"><i class="icon-save" data-bind=" click: $root.saveFav.bind($data)""></i></a>
</span>
</div>
</div>
</div>
// This is the code that does a save via ajax then highlights the element when done.
$.getJSON('#Url.Action("SaveFav","User")', { id: item.userPrefID(), fav: window.JSON.stringify(fav) }, function (result) {
var savedFav = ko.utils.arrayFirst(self.favs(), function (aFav) {
return aFav.userPrefID() == result.userPrefID; // <-- is this the desired fav?
});
// Fav found?
if (savedFav) {
// Update the fav!
savedFav.value(result.value);
}
}).done(function () {
var elementID = "#fav_" + item.userPrefID();
highlightElement(elementID);
});
// Function to highlight the element
function highlightElement(element) {
$(element).effect("highlight", {}, 1500);
}
I would do this the 'knockout' way... use a custom bindingHandler. You shouldn't be directly manipulating DOM in your viewModel, but only touching properties of your viewModel.
Taking this approach, you simply set a boolean value to true when your save is complete... this triggers the highlight effect (the jquery/dom manipulation neatly hidden away from your viewmodel) and when highlight effect completes, the handler sets the boolean back to false. Nice and tidy.
HTML:
<div id="#fav" data-bind="highlight: done">This is a test div</div>
<br />
<button data-bind="click: save">Simulate Save</button>
Javascript:
ko.bindingHandlers.highlight = {
update: function(element, valueAccessor) {
var obs = valueAccessor();
var val = ko.unwrap(obs);
if (val) {
$(element).effect("highlight", {}, 1500, function() {
obs(false);
});
}
}
};
var vm = function() {
var self = this;
self.done = ko.observable(false);
self.save = function() {
self.done(true);
};
}
ko.applyBindings(new vm());
Fiddle:
http://jsfiddle.net/brettwgreen/pd14q4f5/

Resources