Knockout.js Demo




Selected meal

Selected multi meals


All helpers get data from the knockout application viewmodel by using the DataFunc extension.
The value of the editors and select items are synchronized using knockout data-bind attributes, events and the client side api of the editors $(#EditorId).data('api').render(o).
KnockoutDemo/Index.cshtml
<div class="awe-il">
<div data-bind="foreach: meals">
<p>
<input type="text" data-bind="value: Name, event: { change: $parent.itemChanged }" />
<button type="button" class="awe-btn" data-bind="click: $parent.deleteMeal">Delete</button>
</p>
</div>
<div>
<input type="text" placeholder="new meal" data-bind="value: newMeal" />
<button type="button" class="awe-btn" data-bind="click: addMeal">Add Meal</button>
</div>
</div>
<div class="awe-il vtop" style="margin-left: 1em;">
@(Html.Awe().DropdownList(new DropdownListOpt
{
Name = "Meals",
DataFunc = "getKoData('meals', 'Id', 'Name')",
InputAttr = new { data_bind = "value: selectedMeal, event: { change: selMealChange } " }
}))

@(Html.Awe().DropdownList(new DropdownListOpt
{
Name = "Meals2",
DataFunc = "getKoData('meals', 'Id', 'Name')",
InputAttr = new { data_bind = "value: selectedMeal, event: { change: selMealChange } " }
}))

@(Html.Awe().AjaxDropdown("Meals3").DataFunc("getKoData('meals', 'Id', 'Name')")
.HtmlAttributes(null, new { data_bind = "value: selectedMeal, event: { change: selMealChange } " }))

@(Html.Awe().ButtonGroup(new ButtonGroupOpt
{
Name = "Meals4",
DataFunc = "getKoData('meals', 'Id', 'Name')",
InputAttr = new { data_bind = "value: selectedMeal, event: { change: selMealChange } " }
}))

<br />
<br />
@(Html.Awe().CheckBoxList(new CheckBoxListOpt
{
Name = "MealsMulti2",
DataFunc = "getKoData('meals', 'Id', 'Name')",
InputAttr = new { data_bind = "value: selectedMultiMeals, event: { change: selMultiMealsChange } " }
}))

@(Html.Awe().Multiselect(new MultiselectOpt
{
Name = "MealsMulti",
DataFunc = "getKoData('meals', 'Id', 'Name')",
InputAttr = new { data_bind = "value: selectedMultiMeals, event: { change: selMultiMealsChange } " }
}))
</div>

<div><br /><div class="elabel">Selected meal</div><input type="text" data-bind="value: selectedMeal, event: { change: selMealChange }" /></div>
<div><br /><div class="elabel">Selected multi meals</div><input type="text" data-bind="value: selectedMultiMeals, event: { change: selMultiMealsChange }" /></div>
<div>
<br />
<div class="elabel"></div>
@(Html.Awe().TextBox("awetxt")
.HtmlAttributes(null, new { data_bind = "value: selectedMeal, event: { change: selMealChange }" })
.FormatFunc("aweUtils.prefix('value is: ')")
.Numeric(o => o.Min(163).Step(2)))
</div>

<div style="margin-top: 1em;">
@(Html.Awe().Grid("GridClientData")
.DataFunc("getGridData")
.Height(250)
.Groupable(false)
.Mod(o => o.PageInfo())
.Resizable()
.Columns(
new Column { Bind = "Id", Width = 75, Groupable = false, Resizable = false },
new Column { Bind = "Name" }))
</div>

@section scripts
{
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<script>

function AppViewModel() {
var self = this;
var newCounter = 1000;
var meals = @Html.Raw(DemoUtils.Encode(DemoCache.Meals1));

self.meals = ko.mapping.fromJS(meals);
self.selectedMeal = ko.observable(@DemoCache.Meals1[1].Id);
self.selectedMultiMeals = ko.observable(JSON.stringify(@Html.Raw(DemoUtils.Encode(new []{ DemoCache.Meals1[1].Id, DemoCache.Meals1[2].Id}))));
self.newMeal = ko.observable('');

self.addMeal = function () {
self.meals.push(ko.mapping.fromJS({ Id: newCounter++, Name: self.newMeal() }));
self.newMeal('');
};

self.deleteMeal = function (row) {
self.meals.remove(row);
};

self.itemChanged = onItemsChange;
self.meals.subscribe(onItemsChange);

function onItemsChange() {
var list = ko.mapping.toJS(self.meals);
renderEditors(list, ["Meals", "Meals2", "Meals3", "Meals4", "MealsMulti", "MealsMulti2"], "Id", "Name");
$('#GridClientData').data('api').load();
return true;
}

self.selMealChange = function () {
var list = ko.mapping.toJS(self.meals);
renderEditors(list, ["Meals", "Meals2", "Meals3", "Meals4"], "Id", "Name");
$('#awetxt').data('api').render();
return true;
};

self.selMultiMealsChange = function () {
var list = ko.mapping.toJS(self.meals);
renderEditors(list, ["MealsMulti", "MealsMulti2"], "Id", "Name");
return true;
};

}

var appvm = new AppViewModel();

ko.applyBindings(appvm);

function getGridData(sgp) {
var gp = aweUtils.getGridParams(sgp);

// clone items to avoid grid sorting items in other editors
var items = ko.mapping.toJS(appvm["meals"]);

return aweUtils.gridModelBuilder({
gp: gp,
items: items,
key: "Id"
});
}

// utility functions
function renderEditors(list, ids, kprop, cprop) {
$.each(ids, function (i, val) {
renderEditor(list, val, kprop, cprop);
});
}

function renderEditor(list, id, kprop, cprop) {
var $editor = $('#' + id);
var o = $editor.data('o');
o.lrs = toKeyContent(list, kprop, cprop);
$editor.data('api').render(o);
}

function toKeyContent(list, key, con) {
return $.map(list, function (o) { return { k: o[key], c: o[con] }; });
}

function getKoData(collName, kprop, cprop) {
return function () {
return toKeyContent(ko.mapping.toJS(appvm[collName]), kprop, cprop);
};
}
</script>
}




Comments