KnockoutJS:Agregar propiedades y funciones observables a objetos en un ObservableArray generado por mapeo

StackOverflow https://stackoverflow.com/questions/8401799

Pregunta

Soy nuevo en KnockoutJS, y estoy atascado al intentar agregar propiedades y métodos adicionales a los objetos generados en el ko.observableArray() como fue creado por el mapping enchufar.


Aquí es donde estoy haciendo:

  • Tengo una matriz JSON de Users
  • He creado el ko.observableArray() con el complemento de mapeo
  • Tengo una plantilla que crea una fila de tabla para cada uno. User, hasta ahora todo bien :o)


Esto es lo que estoy tratando de hacer:

Cada User tiene una propiedad llamada 'IsActive' - Me gustaría data-bind un evento de clic a un método en cada uno User objeto que alterna esto 'IsActive' propiedad.

Esta pregunta parecía prometedora., pero me parece una duplicación innecesaria tener que declarar todo el modelo de vista en JS (¡a menos que esa sea la forma en que tengo que hacerlo!). ¿Es posible simplemente extender el objeto generado?

Estaba pensando más en esta línea., donde hay una manera de declarar propiedades o métodos adicionales y hacer que extiendan el mapping objetos generados, pero este artículo se ocupa de objetos individuales en lugar de extender objetos en una matriz generada.


Aquí está el código: http://jsfiddle.net/yZkSf/2/ (Aún no funciona en JS Fiddle, pero seguiré jugando con él y actualizaré este enlace cuando lo haga funcionar).

gracias por su ayuda

¿Fue útil?

Solución

Hay varias opciones que podrías considerar.

-Uno es utilizar el create llamar de vuelta para controlar cómo se crean sus objetos de "usuario".Puede definir los observables usted mismo y agregar funcionalidad adicional o llamar al complemento de mapeo en el objeto de usuario individual y luego agregar funcionalidad adicional.

Sería algo como: http://jsfiddle.net/rniemeyer/fkVaK/

-De lo contrario, puede colocar la función "alternar" en su modelo de vista y luego pasarle el objeto "usuario".

Una buena manera con 1.3 es usar ko.dataFor junto con algo como la funcionalidad de delegación de eventos en vivo/delegar/en jQuery.Seria como: http://jsfiddle.net/rniemeyer/FkjNr/

//unobtrusive event handler
$(".toggle").live("click", function() {
    var user = ko.dataFor(this);
    if (user) {
       viewModel.toggleIsActive(user);
    }
});

Si no desea utilizar la delegación de eventos, puede pasar el elemento directamente mediante una función anónima como: http://jsfiddle.net/rniemeyer/GpQtN/

EDITAR:a partir de 2.0, los datos actuales se pasan automáticamente al controlador cuando se utilizan enlaces de clic/evento, por lo que puede hacer lo siguiente:

<a href="#" data-bind="click: $root.toggleIsActive"><span data-bind="text: IsActive"></span></a>

Otros consejos

Esto es lo que se me ocurrió usando tus respuestas y las de Ryan...parece funcionar.Por favor, dejen sus comentarios, ya que soy nuevo en Knockout y tengo curiosidad por saber si este es un buen enfoque.

JS:

$(function() {
    $.get("users/getUsers", function(r){
        var vm = ko.mapping.fromJS(r, {
            users: {
                create: function(user){
                    var methods = {
                        toggleIsActive: function(u){u.IsActive(!u.IsActive());},
                        foo: function(u){console.log(u);},
                        bar: function(u){/*whatever*/},   
                    }
                    return $.extend(ko.mapping.fromJS(user.data), methods);
                }
            }
        });
        ko.applyBindings(vm);
    }, 'json');
});

DOM:

<!-- ko foreach: users -->
   <a href="#" data-bind="click: toggleIsActive"><span data-bind="text: IsActive"></span></a>
<!-- /ko -->

Encontré una manera de hacerlo, pero significa recorrer los objetos generados en la matriz una vez que se han creado.Preferiría una forma de lograr el mismo resultado sin el bucle adicional.

EDITAR: ¡Como sugiere RP Niemeyer en su respuesta! ;o)

De todos modos, una forma de agregar propiedades a un objeto existente es usar jQuery extender() para combinar los objetos.

Primero, declara las propiedades y funciones adicionales en un nuevo objeto:

var userModel = {
    toggleIsActive: function() {
        console.log('toggleIsActive called: before: ' + this.IsActive());
        this.IsActive(!this.IsActive());
        // todo: save!
        console.log('toggleIsActive called: after: ' + this.IsActive());
    }
}

Luego, después de la ko.mapping.fromJS() llamar, pero antes del ko.applyBindings() llamar, recorra los objetos en la matriz generada y extiéndalos:

viewModel.users = ko.mapping.fromJSON(/* get JSON */);

for (var i = 0; i < viewModel.users().length; i++) {
    $.extend(viewModel.users()[i], userModel);
}

ko.applyBindings(viewModel);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top