Reputation: 367
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 -->
Upvotes: 0
Views: 650
Reputation: 4860
First, you want to remove all this logic from the view and move it to a viewModel.
This will give you
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>
Upvotes: 2