2012-02-21 15 views
9

Estoy usando tanto Knockout (versión 2.0) como jQuery Mobile (versión 1.0.1) en el mismo proyecto. El problema es con datos vinculantes para seleccionar listas. jQuery Mobile presenta listas de selección de una manera en la que el valor aparentemente seleccionado y la lista real son elementos separados. Esto se soluciona ejecutandoKnockout y jQuery Mobile: datos de enlace para seleccionar listas

$(element).selectmenu('refresh', true); 

después de cambiar la lista o el valor seleccionado. Según mi experiencia, esta es una situación peligrosa ya que los desarrolladores a menudo olvidan actualizar la lista de selección.

Para facilitar esto, escribí mi propio manipulador de encuadernación Knockout. Los valores se unen a la lista de selección con el siguiente código:

<select name="selection" data-bind="jqmOptions: values, optionsValue: 'id', optionsText: 'name', value: selectedValue"> 
</select> 

La implementación de jqmOptions:

ko.bindingHandlers.jqmOptions = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     if (typeof ko.bindingHandlers.options.init !== 'undefined') { 
      ko.bindingHandlers.options.init(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 
    }, 

    update: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     if (typeof ko.bindingHandlers.options.update !== 'undefined') { 
      ko.bindingHandlers.options.update(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 

     var instance = $.data(element, 'selectmenu'); 
     if (instance) { 
      $(element).selectmenu('refresh', true); 
     } 
    } 
}; 

Este utiliza el nativo options vinculante, pero además de eso, se actualiza automáticamente listas de selección después de cambiar los valores de la lista. Sin embargo, hay un problema con esto cuando estoy cambiando el valor seleccionado. Si primero configuro los valores de la lista, mi jqmOptions actualiza la lista de selección, pero en ese momento, el valor seleccionado todavía no está establecido. Terminé con una lista de selección, que tiene todos los valores correctos e internamente se selecciona la opción correcta, pero jQuery Mobile todavía muestra el valor predeterminado como seleccionado.

this.values(someArrayOfValues); 
this.selectedValue(oneOfTheArrayValues); 

Knockout no permite que fije primero el valor seleccionado, y luego poner los valores de la lista, ya que en este caso no hay valores permitidos cuando estoy estableciendo el valor seleccionado. Por lo tanto, el valor seleccionado siempre está indefinido.

¿Existe alguna manera de escribir un enlace personalizado Knockout que actualice el elemento de lista de selección en ambos casos: al cambiar el valor de la lista y al cambiar el valor seleccionado?

Actualmente me resolver esta situación con la siguiente código:

this.values(someArrayOfValues); 
this.selectedValue(oneOfTheArrayValues); 
this.values(someArrayOfValues); 

Esto no es una solución muy elegante y sin embargo me gustaría resolverlo mejor.

Respuesta

4

Por mi experiencia personal (con jquery mobile 1.1.0 y 2.1.0 knockoutjs), sólo he utilizado jqmoptions (como se ve en el primer post) que se une a tener un nocaut válida la unión a un selecto.Para realizar trabajos de unión de 'valor' con seleccionar, simplemente declarará como primera en la unión

<select name="myname" id="myid" data-bind="value: myvalue, jqmoptions: myvalues, optionsValue: 'id', optionsText: 'desc'"></select> 

Parece que el orden es obligatoria: http://goo.gl/nVbHc

+0

Eche un vistazo a este artículo del blog: http://pieterderycke.wordpress.com/2012/09/22/creating- a-custom-knockout-binding-for-the-jquery-mobile-listview/Explica un enlace de lista de visitas personalizado para jquery mobile. – MuSTaNG

14

Terminé resolviéndome. Escribí mi propia jqmValue vinculante:

ko.bindingHandlers.jqmValue = { 
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     if (typeof ko.bindingHandlers.value.init !== 'undefined') { 
      ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 
    }, 

    update: function (element, valueAccessor, allBindingsAccessor, viewModel) { 
     if (typeof ko.bindingHandlers.value.update !== 'undefined') { 
      ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 

     var instance = $.data(element, 'selectmenu'); 
     if (instance) { 
      $(element).selectmenu('refresh', true); 
     } 
    } 
}; 

El código de selección de la lista se cambia a lo siguiente:

ya he intentado implementar esto ayer antes de hacer la pregunta, pero al parecer lo escribí mal entonces porque no funcionó. Sin embargo, ahora con un par de ojos frescos logré implementarlo correctamente, así que con suerte esta respuesta resuelve el problema para otros usuarios de Knockout y jQuery Mobile también.

+0

funciona muy bien! Gracias Ville! –

+2

Estaba estirando mi cabello antes de encontrar su Q & A. Gracias por compartir –

+0

¿Has actualizado esto para knockout 3? esto no parece funcionar para mí ahora –

0

Sólo por la claridad, la mejor solución ahora para KO 3 .x sería:

ko.bindingHandlers.jqmValue = { 
    init: function(element, valueAccessor, allBindingsAccessor, viewModel) { 
     if (typeof ko.bindingHandlers.value.init !== 'undefined') { 
     ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 
    }, 
    update: function(element, valueAccessor, allBindingsAccessor, viewModel) { 
     var instance; 
     if (typeof ko.bindingHandlers.value.update !== 'undefined') { 
     ko.bindingHandlers.value.update(element, valueAccessor, allBindingsAccessor, viewModel); 
     } 
     instance = $.data(element, 'mobile-selectmenu'); 
     if (instance) { 
     $(element).selectmenu('refresh', true); 
     } 
    } 
    }; 

Y el uso coincidente HTML:

<select data-bind="options: optionsList, optionsValue: 'Id', optionsText: 'Title', jqmValue: knockoutobservable"></select> 
0

utilizando tanto Knockout 3.3 + jQuery Mobile 1.4.5 y también tenía el mismo problema cuando tuve varias selecciones, que vinculen a uno el valor

<select id="myselect1" data-bind="options: modelsA-Z, value: myModel"></select> 
<select id="myselect2" data-bind="options: modelsFamous, value: myModel"></select> 

primera/segunda SELECT no muestra el valor de inicio y segundo no se actualiza después ... finalmente utilizar por debajo de la unión: (sustituir por encima del valor: myModel -> jqmValue: myModel)

ko.bindingHandlers.jqmValue = { 
    init: function (element, valueAccessor) { 
     var result = ko.bindingHandlers.value.init.apply(this, arguments); 
     try { 
      $(element).selectmenu("refresh"); 
     } catch (x) {} 
     return result; 
    }, 
    update: function (element, valueAccessor) { 
     ko.bindingHandlers.value.update.apply(this, arguments); 
     var value = valueAccessor(); 
     var valueUnwrapped = ko.utils.unwrapObservable(value); 
     try { 
      $(element).selectmenu("refresh"); 
     } catch (x) {} 
    } 
};