简体   繁体   中英

How to use index in computed observable [knockout.js]

Below is some example code. I need to use the items index in a computed variable, but I cant figure out how to do it without accessing the variable holding the view model app.

<template type="text/ko-template" id="rowTemplate">
    <li><span data-bind="text: number"></span> = <span data-bind="text: word"></span></li>
</template>

<ul data-bind="template: { name: 'rowTemplate', foreach: rowArray }"></ul>

<script>

    function RowModel(word) {
        var self = this;
        self.word = ko.observable(word);
        self.number = ko.computed({
            read: function(){
                return "#" + app.rowArray.indexOf(self); // This works, but is far from ideal.
            },
            deferEvaluation: true
        });

    };

    function ViewModel() {
        var self = this;
        self.rowArray = ko.observableArray([
            new RowModel('Zero'),
            new RowModel('One'),
            new RowModel('Two'),
        ]);
    };

    var app = new ViewModel();
    ko.applyBindings(app);

</script>

I've tried changing the line with the comment to many things, such as $index , self.index() , and all similar combos with $parentContext , etc.

Instead of using computed you can go with $index in view which gives the current index of array.

view:

<template type="text/ko-template" id="rowTemplate">
    <li><span data-bind="text: '#'+($index()+1)"></span> = <span data-bind="text: word"></span></li>
</template>

<ul data-bind="template: { name: 'rowTemplate', foreach: rowArray }"></ul>

viewModel:

function RowModel(word) {
    var self = this;
    self.word = ko.observable(word);
};

function ViewModel() {
    var self = this;
    self.rowArray = ko.observableArray([
        new RowModel('Zero'),
        new RowModel('One'),
        new RowModel('Two'),
    ]);
};

var app = new ViewModel();
ko.applyBindings(app);

working sample here

I posted this question as a simplification of my true 'problem', which may not have been the best idea. My intention was to access the context in the computed observable, thus my mention of $parentContext .

My research has lead to the following stack overflow question and answers, regarding the 'context': How can I use knockout's $parent/$root pseudovariables from inside a .computed() observable?

Knockout does provide some functions for getting the context, but they do not work in this scenario (they are useful in event handlers only):

ko.dataFor(element) - returns the data that was available for binding against the element ko.contextFor(element) - returns the entire binding context that was available to the DOM element.

Thus it seems the best solution is very similar to my original question, but it explicitly stores the 'context' on the model object, to then be used in the computed observable (as discussed further in the aforementioned SO questions and answers)

function RowModel(word, context) {
    var self = this;
    self.word = ko.observable(word);
    self.context = context; // Save the 'context' to the object.
    self.number = ko.computed({
        read: function() {
            return "#" + self.context.rowArray.indexOf(self); // Do something with the 'context'.
        },
        deferEvaluation: true
    });
};

function ViewModel() {
    var self = this;
    self.rowArray = ko.observableArray([
        new RowModel('Zero', self),
        new RowModel('One', self),
        new RowModel('Two', self),
    ]);
};

This sounds like a bit of a hassle, but it seems that knockout is basically doing the same 'under the hood' to compute $index :

Unlike the other binding context properties, $index is an observable and is updated whenever the index of the item changes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM