Filter users by one keyword in a nested observable array

I am trying to filter out my usersobservableArray that has nested observableArray keywords
based on the keywords of the observable array on my view model.

When I try to use ko.utils.arrayForEach, I get an exception. See the code below also posted in this jsfiddle

function User(id, name, keywords){
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        keywords: ko.observableArray(keywords),
        isVisible: ko.dependentObservable(function(){

        var visible = false;            
        if (viewModel.selectedKeyword() || viewModel.keywordIsDirty()) {
            ko.utils.arrayForEach(keywords, function(keyword) {
                if (keyword === viewModel.selectedKeyword()){
                    visible = true;
                }
            });
            if (!visible) {
                viewModel.users.remove(this);
            }
        }
        return visible;
      })
    }
};

function Keyword(count, word){
    return{
        count: ko.observable(count),
        word: ko.observable(word)
    }
};

var viewModel = {
    users: ko.observableArray([]),
    keywords: ko.observableArray([]),
    selectedKeyword: ko.observable(),
    keywordIsDirty: ko.observable(false)
}

viewModel.selectedKeyword.subscribe(function () {
    if (!viewModel.keywordIsDirty()) {
        viewModel.keywordIsDirty(true);
    }
});

ko.applyBindings(viewModel);

for (var i = 0; i < 500; i++) {
    viewModel.users.push(
        new User(i, "Man " + i, ["Beer", "Women", "Food"])
    )
}

viewModel.keywords.push(new Keyword(1, "Beer"));
viewModel.keywords.push(new Keyword(2, "Women"));
viewModel.keywords.push(new Keyword(3, "Food"));
viewModel.keywords.push(new Keyword(4, "Cooking"));

And view code:

<ul data-bind="template: { name: 'keyword-template', foreach: keywords }"></ul><br />
<ul data-bind="template: { name: 'user-template', foreach: users }"></ul>

<script id="keyword-template" type="text/html">
    <li>
        <label><input type="radio" value="${word}" name="keywordgroup" data-bind="checked: viewModel.selectedKeyword" /> ${ word }<label>
    </li>    
</script>

<script id="user-template" type="text/html">
    <li>
        <span data-bind="visible: isVisible">${ $data.name }</span>
    </li>    
</script>
+3
source share
1 answer

Your isVisibledependentObservable has created a dependency on itself and is recursively trying to evaluate itself based on this line:

        if (!visible) {
            viewModel.users.remove(this);
        }

, viewModel.users, remove observableArray, . , .

, - . ( , ).

, , viewModel, - filteredUsers. .

:

viewModel.filteredUsers = ko.dependentObservable(function() {
    var selected = viewModel.selectedKeyword();
    //if nothing is selected, then return an empty array
    return !selected ? [] : ko.utils.arrayFilter(this.users(), function(user) {
        //otherwise, filter on keywords.  Stop on first match.
        return ko.utils.arrayFirst(user.keywords(), function(keyword) {
            return keyword === selected;
        }) != null; //doesn't have to be a boolean, but just trying to be clear in sample
    });
}, viewModel);

, dependObservables , , , . , selectedKeyword, , Keyword .

http://jsfiddle.net/rniemeyer/mD8SK/

, .

+5

All Articles