2011-09-13 10 views
32

Cuando vinculo datos numéricos en mi modelo de vista usando knockout, se muestra correctamente pero cambia el tipo de datos a cadena si el usuario cambia el valor de la etiqueta de entrada. El problema al enviar cadena es que el servidor espera un valor numérico sin conversión implícita disponible.Knockout.js: formato de entrada de tiempo y restricción de valor

¿Alguna manera de decirle a nocaut para mantener el tipo de datos del valor de propiedad original?

Mi código de ejemplo que coincide con los nombres de modelo de vista a los nombres de etiqueta de entrada. Uso un knockout discreto para hacer las fijaciones, que funciona bien.

// Bind the first object returned to the first view model object 
// FNS is the namespace, VM is the view model 
FNS.VM.Items[0] = ko.mapping.fromJS(data.Items[0]); 

// For each property found, find the matching input and bind it 
$.each(FNS.VM.Items[0], function (indexInArray, valueOfElement) { 
    var attrName = indexInArray; 
    var attrValue; 
    if (typeof valueOfElement == "function") 
     attrValue = valueOfElement(); 
    else 
     attrValue = valueOfElement; 

    var a = $('input[name="' + attrName + '"][type="checkbox"]'); 
    if (a.length) 
     a.dataBind({ checked: 'VM.Items[0].' + attrName }); 

    var b = $('input[name="' + attrName + '"][type="radio"]'); 
    if (b.length) 
     b.dataBind({ checked: 'VM.Items[0].' + attrName }); 

    var c = $('input[name="' + attrName + '"][type="text"]'); 
    if (c.length) 
     c.dataBind({ value: 'VM.Items[0].' + attrName }); 
}); 
ko.applyBindings(FNS); 

Respuesta

49

Aquí hay un hilo con algunas técnicas diferentes para mantener el valor numérico: https://groups.google.com/d/topic/knockoutjs/SPrzcgddoY4/discussion

Una opción es empujar esta preocupación en su modelo de vista y crear un numericObservable para usar en lugar de un observable normal. Podría verse como:

ko.numericObservable = function(initialValue) { 
    var _actual = ko.observable(initialValue); 

    var result = ko.dependentObservable({ 
     read: function() { 
      return _actual(); 
     }, 
     write: function(newValue) { 
      var parsedValue = parseFloat(newValue); 
      _actual(isNaN(parsedValue) ? newValue : parsedValue); 
     } 
    }); 

    return result; 
}; 

muestra: http://jsfiddle.net/rniemeyer/RJbdS/

Otra opción es manejar esto con una unión personalizado. En lugar de utilizar el enlace value, puede definir un enlace numericValue y usarlo en su lugar. Podría verse como:

ko.bindingHandlers.numericValue = { 
    init : function(element, valueAccessor, allBindings, data, context) { 
     var interceptor = ko.computed({ 
      read: function() { 
       return ko.unwrap(valueAccessor()); 
      }, 
      write: function(value) { 
       if (!isNaN(value)) { 
        valueAccessor()(parseFloat(value)); 
       }     
      }, 
      disposeWhenNodeIsRemoved: element 
     }); 

     ko.applyBindingsToNode(element, { value: interceptor }, context); 
    } 
}; 

muestra: http://jsfiddle.net/rniemeyer/wtZ9X/

+1

Su respuesta me llevan a [esta respuesta] (http://www.knockmeout.net/2011/03/reacting-to-changes-in- knockoutjs.html) en ** Depende de dependientes dependientes **, que colectivamente responde mi pregunta. Gracias –

+0

Nota rápida: leyendo los commits de Knockout veo que RP Niemeyer hace referencia a su propia respuesta aquí con una nota rápida: https://github.com/knockout/knockout/pull/1334 Hay una forma más compatible de invocar la línea ko. bindingHandlers.value.init ... –

+5

Cualquiera que lea esto, tenga en cuenta que dependientebservible() ahora se llama calculado() – Quango

Cuestiones relacionadas