Pregunta

Estoy tratando de filtrar mi users Observablearray que tiene una palabra clave anidadas Observablearray
Basado en las palabras clave ObservableArray en mi ViewModel.

Cuando intento usar ko.utils.arrayForEach Obtengo una excepción de desbordamiento de pila. Vea el código a continuación, también publicado en este 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"));

Y el código de vista:

<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>
¿Fue útil?

Solución

Su isVisible DependentObservable ha creado una dependencia de sí misma y está tratando de evaluar recursivamente en función de esta línea:

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

Por lo tanto, esto crea una dependencia de ViewModel.users, porque RemoLe tiene que acceder a la matriz subyacente de ObservablearRay para eliminar al usuario. En el momento en que se modifica la matriz, se notifica a los suscriptores y uno de los suscriptores será en sí mismo.

Por lo general, es mejor no cambiar el estado de ningún observable en un dependiente. Puede suscribirse manualmente a los cambios a un dependiente OBServable y realizar sus cambios allí (siempre que el dependiente seable no dependa de lo que esté cambiando).

Sin embargo, en este caso, probablemente crearía un dependiente que se puede reservar en el nivel de modelado de View filteredUsers. Luego, devuelva una versión de la matriz de usuarios que se filtra.

Puede verse así:

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);

Tampoco debe necesitar la bandera sucia, ya que dependientes se vuelven a activar cuando cualquier observable que accedan hayan cambiado. Entonces, dado que accede a SelectionKeyword, se reevaluará cada vez que cambie SelectSKeyword.

http://jsfiddle.net/rniemeyer/md8sk/

Espero haber entendido adecuadamente tu escenario.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top