2011-07-19 13 views
8

Estoy vinculando una lista de objetos a un select usando knockout. Clase de objeto puede tener cualquier número de propiedadesEl enlace de opciones de selección única con la validación de jQuery no funciona

<select id="TheProperty_City" 
     name="TheProperty_City" 
     class="required" 
     data-bind="options: cityList, 
        optionsText: 'Name', 
        value: selectedCity, 
        optionsCaption: '--select the city--'" /> 

Esto funciona perfectamente bien y puedo usar viewModel.selectedCity().Name o viewModel.selectedCity().Value para los elementos de carga del niño.

Mi problema es con la validación de jQuery. Si dejo la declaración como la anterior, jQuery no restablece el error incluso después de la selección.

Lo arreglé especificando optionsValue en el enlace, pero luego el selectedCity devuelve el valor escalar y no el objeto completo. ¿Alguna idea de cómo preservar el comportamiento del objeto o hacer la validación de manera diferente?

<select id="TheProperty_City" 
     name="TheProperty_City" 
     class="required" 
     data-bind="options: cityList, 
        optionsText: 'Name', 
        optionsValue: 'Value', //added the optionsValue 
        value: selectedCity, 
        optionsCaption: '--select the city--'" /> 

El error se queda allí cuando optionsValue no se especifica:

Without the OptionsValue

Aquí está mi reloj Objeto en selectedCity:

viewModel.selectedCity() in watch returns an object

Aquí está un objeto Reloj en selectedCity cuando optionsValue está especificado:

With OptionsValue

Respuesta

8

El problema es que cuando se trata de objetos como el valor, las option elementos tienen su valor ajustado en "". La validación de jQuery falla debido a esto. Puede escribir un enlace o un enlace envoltorio para el enlace options que atraviesa y simplemente establecerlos en un valor, pero no creo que sea preferible seguir esa ruta.

Una opción decente es almacenar el valor y usar un dependienteDebservable para representar el objeto seleccionado actualmente.

Sería como:

var viewModel = { 
    cityList: [{ Name: "Madison", Value: "MSN" }, { Name: "Milwaukee", Value: "MKE" }, { Name: "Green Bay", Value: "GRB" }], 
    selectedCityValue: ko.observable() 
}; 

viewModel.selectedCity = ko.dependentObservable(function() { 
    var value = this.selectedCityValue(); 
    return ko.utils.arrayFirst(this.cityList, function(city) { 
     return city.Value === value; 
    }); 
}, viewModel); 

Con una unión como:

<select id="TheProperty_City" name="TheProperty_City" class="required" 
    data-bind="options: cityList, 
    optionsText: 'Name', 
    optionsValue: 'Value', 
    value: selectedCityValue, 
    optionsCaption: '--select the city--'" /> 

Muestra aquí: http://jsfiddle.net/rniemeyer/EgCM3/

+3

Gracias, eso es lo que tengo en su lugar como una solución, pero es tedioso hacerlo para todas las listas desplegables. Mi script knockoutjs está creciendo rápidamente y me pregunto si vale la pena el esfuerzo ya que se pierden los helpers de control mvc Html, las anotaciones de datos de ViewModel del servidor y el soporte de validación incorporado. Por supuesto, la unión de datos es excelente. De todos modos, haré esto como una respuesta para ayudar a otros buscadores. –

+0

¿Cómo implementaría un enlace personalizado para solucionar esto? – Jason

+0

Tuve el mismo problema y lo resolví de la misma manera que RP Niemeyer lo describió. Todavía me pregunto cómo hacerlo más agradable, porque como escribió Jason no se puede leer en grandes modelos de vista. –

5

solución bastante ordenada sería añadir optionsAfrerRender parámetro para opciones de encuadernación . Suponiendo que en el objeto 'selectedCity' hay un campo 'cityId', puede asignarlo a un valor de opción. Por favor, compruebe la siguiente solución basada en el ejemplo:

<select id="TheProperty_City" 
    name="TheProperty_City" 
    class="required" 
    data-bind="options: cityList, 
       optionsText: 'Name', 
       value: selectedCity, 
       optionsAfterRender: function(option, item) 
             { option.value = item.cityId; } 
       optionsCaption: '--select the city--'" /> 

uso de este enfoque obtendrá trabajando ambas opciones de cobertura vinculante y validación de jQuery.

+0

buena solución! –

+0

Esto funciona muy bien para evitar las rarezas cuando se integra con los validadores de Bootstrap. – AdjunctProfessorFalcon

1

La respuesta anterior funciona con una advertencia. El primer valor de selección vinculado ("--select the city--") no estará definido, lo que provocará un error.

Si modifica el código para manejar esto, funcionará.

<select id="TheProperty_City" 
name="TheProperty_City" 
class="required" 
data-bind="options: cityList, 
      optionsText: 'Name', 
      value: selectedCity, 
      optionsAfterRender: setOptionValue 
      optionsCaption: '--select the city--'" /> 

Nota: He despojado a cabo todo, desde el modelo de vista excepto por el método setOptionValue por razones de brevedad.

<script type="text/javascript"> 
var vm = { 
    setOptionValue: function(option, item) { 
     if (item === undefined) { 
      option.value = ""; 
     } else { 
      option.value = item.id; 
     } 
    } 
}; 
ko.applyBindings(vm); 

+0

Dando un paso más: en el fundo 'setOptionValue', pase el nombre de la propiedad como un tercer param (' propId'), y luego haga 'option.value = item [propId]'. Esto ahora se puede usar para cualquier menú desplegable con diferentes enlaces de modelo. –

0

Extender sobre la respuesta de Robert, podemos hacer el trabajo función auxiliar por cada desplegable en el modelo de vista no importa el contexto enlace de datos, permitiendo al usuario pasar de una cadena para la derecha propiedad:

JS

self.setOptionValue = function(propId) { 
    return function (option, item) { 
     if (item === undefined) { 
      option.value = ""; 
     } else { 
      option.value = item[propId]; 
     } 
    } 
}; 

HTML

<select class="custom-dropdown" data-bind="options: cityList, 
     optionsAfterRender: setOptionValue('AppointmentTypeId'), value: selectedCityObj, optionsCaption: 'Choose...'" data-validation="required"></select> 
Cuestiones relacionadas