I need to get the $index in a javascript function to implement prev/next buttons for a list of values. The method I found seems cumbersome, perhaps there is a more straightforward way.
Now I do this to get the $index in javascript, then put it in an observable:
<div data-bind="foreach: myarray">
<div data-bind="click: function(data, event){ onclick(data, event, $index()); }"
function onclick(idata, event, index) {
theAppViewModel.choiceindex(index);
On SO I found a small improvement by getting $index from the event:
<div data-bind="foreach: myarray">
<div data-bind="click: onclick"
function onclick(idata, event) {
var context = ko.contextFor(event.target);
theAppViewModel.choiceindex(context.$index());
From a commenter came the method to get the index by searching the array for the selected value, that usually has its own observable, e.g. choice:, like:
var i = TheArray.indexOf(theAppViewModel.choice());
Normally, the length of the array on the page isn't huge, and if it has big objects, you could just search over one of its fields with fun syntax like:
myarray.find(x => x.id === searchvalue);
But I wonder if it isn't possible to access the $index even more directly, without storing in my own observable choiceindex, as the Knockout docs say that $index is already an observable.
Here is a complete sample code to play with:
<!DOCTYPE html>
<html>
<head>
<title>Test Knockout Foreach</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src='https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-min.js'></script>
<style>
.selected {background-color: #f0f0f0;}
</style>
</head>
<body>
<div data-bind="foreach: myarray" style="width: 10em;">
<div data-bind="click: function(data, event){ onclick(data, event, $index()); },
css: { selected: $data == $root.choice() }">
<span data-bind="text: $index"></span>
<span data-bind="text: $data"></span>
</div>
</div>
<input type="button" value="Prev" data-bind="click: onprev" />
<input type="button" value="Next" data-bind="click: onnext" />
<p>
Choice:
<span data-bind="text: choice"></span>
</p>
<p>
Index:
<span data-bind="text: choiceindex"></span>
</p>
<script>
var TheArray = ["apple", "pear", "banana", "coconut", "peanut"];
function onclick(idata, event, index) {
theAppViewModel.choice(idata);
theAppViewModel.choiceindex(index);
//var context = ko.contextFor(event.target);
//theAppViewModel.choiceindex(context.$index());
//theAppViewModel.choiceindex(index);
}
function onprev(idata, event) {
var i = theAppViewModel.choiceindex() - 1;
if (i >= 0) {
theAppViewModel.choice(TheArray[i]);
theAppViewModel.choiceindex(i);
}
}
function onnext(idata, event) {
//var i = theAppViewModel.choiceindex() + 1;
//var dummydata = theAppViewModel.choice();
//var dummy = TheArray.indexOf(dummydata);
var i = TheArray.indexOf(theAppViewModel.choice()) + 1;
if (i < TheArray.length) {
theAppViewModel.choice(TheArray[i]);
theAppViewModel.choiceindex(i);
}
}
function AppViewModel() {
var self = this;
self.myarray = ko.observableArray(TheArray);
self.choice = ko.observable();
self.choiceindex = ko.observable();
}
var theAppViewModel = new AppViewModel();
window.onload = function () {
ko.applyBindings(theAppViewModel);
}
</script>
</body>
</html>
myarray.find(x => x.id === $data.id). Still curious about direct access to the $index observable as the most logical solution, but if nobody has a clue, I can certainly live with your method.