I'm trying to add elements to an empty observable array in response to a user selection (the user clicks on a link to add that element to observable array)
Here is my ko script code:
function mfProduct(data) {
var self = this;
self.MfProductId = data.MfProductId;
self.MfProductName = data.MfProductName;
};
function mfProductViewModel() {
// Data
var self = this;
self.ProdId = ko.observable();
self.ProdName = ko.observable();
self.selectedProducts = ko.observableArray([]);
// Operations
self.addProduct = function () {
if (self.ProdId() != '' && self.ProdId() != undefined) {
self.selectedProducts.push(new mfProduct({ MfProductId: self.ProdId(), MfProductName: self.ProdName() }));
self.ProdId("");
self.ProdName("");
}
};
self.removeProduct = function (mfProduct) {
self.selectedProducts.remove(mfProduct);
};
};
Here is my view markup:
<div class="row">
<div id="selectedProducts" class="col-sm-12" data-bind="foreach: selectedProducts">
<div class="row" style="border: 1px solid red;">
<div class="col-sm-10"><strong data-bind="text: MfProductName"></strong></div>
<div class="col-sm-2"><a href="#" data-bind="click: removeProd"><i class="glyphicon glyphicon-remove-circle"></i></a></div>
</div>
</div>
<div class="form-group">
<div class="col-sm-3">
Select product
</div>
<div class="col-sm-offset-3">
<input type="hidden" id="selectedProdId" data-bind="value: ProdId" value="">
<input type="hidden" id="selectedProdName" data-bind="value: ProdName" value="">
<div id="searchResults" class="ddlContents">
<ul>
<li><a id="00001" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Milky Way</a></li>
<li><a id="00002" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Bocadin</a></li>
<li><a id="00003" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Carlos V</a></li>
<li><a id="00004" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Snickers</a></li>
<li><a id="00005" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Crunch</a></li>
<li><a id="00006" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Power Milch</a></li>
<li><a id="00007" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Toblerone</a></li>
<li><a id="00008" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">KitKat</a></li>
<li><a id="00009" href="#" onmouseover="javascript:markSelected(this);" data-bind="click: addProduct">Cacao</a></li>
</ul>
</div>
</div>
</div>
I added the onmouseover event handler to update the observable properties for productId and productName since I don't know how to send parameters to the click binding (something like javascript:addProduct(id, name);
)
Here is the javascript code for that matter:
$(document).ready(function () {
ko.applyBindings(new mfProductViewModel());
});
function markSelected(anchor) {
// Update the value of the hidden fields with id and Text coming from the "moused over" link.
$("#selectedProdId").val(anchor.id);
$("#selectedProdName").val(anchor.innerText);
};
My intention is to click on any of the links in the unordered list, add the selected product in the mfProductViewModel.selectedProducts
observable collection, and have the Product Name displayed in the <div id="selectedProducts">
section of the view.
Have any of you faced this kind of functionality using KnockOut.js?
Thank you very much for sharing your knowledge.
The available products that can be selected are also a kind of data and therefore belong into the ViewModel, and not the View (HTML file).
function mfProductViewModel() {
// Data
var self = this;
self.selectedProducts = ko.observableArray([]);
self.products = [
new mfProduct({ MfProductId: '00001', MfProductName: 'Milky Way' }),
new mfProduct({ MfProductId: '00002', MfProductName: 'Bocadin' }),
// ...
];
// Operations
self.addProduct = function(data) {
// add a copy to allow that the same item is added more than once
self.selectedProducts.push(new mfProduct(data));
};
// ...
};
and then simply render the list with knockout:
<ul data-bind="foreach: products">
<li><a href="#" data-bind="text: MfProductName, click: $root.addProduct"></a></li>
</ul>
Slightly simplified example: http://jsfiddle.net/vp9Lqxkp/