2012-09-05 9 views
5

instrucciones Folliwing dadas en el documentation, I tiene la siguiente vista de modelo:bucle infinito cuando la conversión de objeto knockout a objeto JavaScript llanura

var newContactViewModel = function() { 
    var self = this; 

    self.Name = ko.observable(); 
    self.Address = ko.observable(); 
    self.City = ko.observable(); 
    self.State = ko.observable(); 
    self.PostalCode = ko.observable(); 

    self.Save = function() { 
     $.ajax({ 
      type: "POST", 
      url: "/contact", 
      data: ko.toJS(self), //infinite loop here 
      success: state.OnSaved 
     }); 
    }; 
}; 

Cuando se llama al método self.Save, se produce un bucle infinito. Chrome realidad informa del error como:

Uncaught RangeError: Maximum call stack size exceeded

Si uso ko.mapping.toJS(self) en lugar de ko.toJS(self), cuando me siento un error poco más revelador, pero no "mensaje" de error real:

infinite loop error

Si yo intercambie ko.toJS(self) con algo como { Name: self.Name(), Address: self.Address() /* etc */ }, entonces todo funciona bien. Parece que está intentando convertir el método Save y volver a llamar al método como resultado.

Hay un error en KnockoutJS o hay un problema cuando lo uso. Prefiero lo último. ¿Pensamientos?

Respuesta

14

Encontré el problema con el código. ko.toJS preserva las funciones en el objeto para que pueda mapearlo bien. Sin embargo, jquery invocará todas las funciones en el objeto de datos para intentar obtener un valor. Esto a su vez causa el ciclo infinito.

Necesita marcar la función Save para no se pueda mapear. Lamentablemente, la función toJS no parece poder hacer eso. Mantendrá a todos los miembros del objeto. El plugin de mapeo afortunadamente te permite hacer eso.

Para excluir un miembro, establezca la opción ignore en una matriz que contenga 'Save' e ignorará el miembro Save cuando se asigne.

var data = ko.mapping.toJS(self, { 
    ignore: ['Save'] 
}); 

Si usted no está usando el plugin de mapeo, que siempre tiene la opción de quitar la función del objeto Save JS.

self.Save = function() { 
    $.ajax({ 
     type: "POST", 
     url: "/contact", 
     data: self.ToData(), 
     success: state.OnSaved 
    }); 
}; 
self.ToData = function() { 
    var data = ko.toJS(self); 
    delete data.Save; // remove functions 
    delete data.ToData; 
    return data; 
}; 

Por otro lado, sugeriría que no intente utilizar la instancia del modelo de visualización como datos de sus llamadas. Yo crearía explícitamente el objeto de datos en su lugar. Claro que tiene el potencial de ser muy largo, pero es un enfoque que muy probablemente siempre funcionará.

self.ToData = function() { 
    return ko.toJS({ 
     Name: self.Name, 
     Address: self.Address, 
     City: self.City, 
     State: self.State, 
     PostalCode: self.PostalCode 
    }); 
}; 
+0

Eso es realmente información útil, porque yo estaba teniendo problemas con modelos Backbone donde estaba añadiendo una gran cantidad de referencias a las colecciones de los padres, etc. Sin embargo, esto es sólo una solución real, creo que, si está haciendo manualmente la conversión. No ayuda si ko.toJS se usa internamente en otro código de biblioteca. – neverfox

+0

buena solución para una decisión de diseño completamente desastrosa. Lo que francamente me enfurece en este momento es que no me di cuenta de este comportamiento durante meses y esencialmente se deja como 'por diseño' https://github.com/knockout/knockout/pull/1079 - esto necesita ser configurable –

Cuestiones relacionadas