Estoy creando una interfaz de usuario de permisos, tengo una lista de permisos con una lista de selección junto a cada permiso. Los permisos están representados por una matriz observable de objetos que están vinculados a una lista de selección:
<div data-bind="foreach: permissions">
<div class="permission_row">
<span data-bind="text: name"></span>
<select data-bind="value: level, event:{ change: $parent.permissionChanged}">
<option value="0"></option>
<option value="1">R</option>
<option value="2">RW</option>
</select>
</div>
</div>
Ahora el problema es el siguiente: el evento de cambio se genera cuando la interfaz de usuario se completa por primera vez. Llamo a mi función ajax, obtengo la lista de permisos y luego se genera el evento para cada uno de los elementos de permiso. Este no es realmente el comportamiento que quiero. Quiero que se genere solo cuando un usuario realmente selecciona un nuevo valor para el permiso en la lista de selección , ¿cómo puedo hacerlo?
fuente
select
elemento. Sin embargo, incluso cuando el valor inicial de la selección coincidía con una de las opciones, aún desencadenaba elchange
evento. Cuando implementé esteif
bloque simple en el controlador, todo funcionó como se esperaba. Pruebe este método primero. ¡Gracias, @Sarath!Esto es solo una suposición, pero creo que está sucediendo porque
level
es un número. En ese caso, elvalue
enlace activará unchange
evento para actualizarlevel
con el valor de la cadena. Por lo tanto, puede solucionar esto asegurándose de quelevel
sea una cadena para comenzar.Además, la forma más "Knockout" de hacer esto es no usar controladores de eventos, sino usar observables y suscripciones. Haga
level
un observable y luego agregue una suscripción, que se ejecutará cada vez quelevel
cambie.fuente
Aquí hay una solución que puede ayudar con este extraño comportamiento. No pude encontrar una mejor solución que colocar un botón para activar manualmente el evento de cambio.
EDITAR: Tal vez un enlace personalizado como este podría ayudar:
ko.bindingHandlers.changeSelectValue = { init: function(element,valueAccessor){ $(element).change(function(){ var value = $(element).val(); if($(element).is(":focus")){ //Do whatever you want with the new value } }); } };
Y en su atributo de enlace de datos seleccionado agregue:
fuente
Utilizo este enlace personalizado (basado en este violín de RP Niemeyer, vea su respuesta a esta pregunta), que asegura que el valor numérico se convierta correctamente de cadena en número (como sugiere la solución de Michael Best):
Javascript:
ko.bindingHandlers.valueAsNumber = { init: function (element, valueAccessor, allBindingsAccessor) { var observable = valueAccessor(), interceptor = ko.computed({ read: function () { var val = ko.utils.unwrapObservable(observable); return (observable() ? observable().toString() : observable()); }, write: function (newValue) { observable(newValue ? parseInt(newValue, 10) : newValue); }, owner: this }); ko.applyBindingsToNode(element, { value: interceptor }); } };
HTML de ejemplo:
<select data-bind="valueAsNumber: level, event:{ change: $parent.permissionChanged }"> <option value="0"></option> <option value="1">R</option> <option value="2">RW</option> </select>
fuente
Si usa un valor observable en lugar de uno primitivo, la selección no generará eventos de cambio en el enlace inicial. Puede seguir vinculándose al evento de cambio, en lugar de suscribirse directamente al observable.
fuente
Rápido y sucio, utilizando una simple bandera:
var bindingsApplied = false; var ViewModel = function() { // ... this.permissionChanged = function() { // ignore, if flag not set if (!flag) return; // ... }; }; ko.applyBindings(new ViewModel()); bindingsApplied = true; // done with the initial population, set flag to true
Si esto no funciona, intente ajustar la última línea en un setTimeout (); los eventos son asíncronos, por lo que tal vez el último aún esté pendiente cuando applyBindings () ya regresó.
fuente
Tuve un problema similar y acabo de modificar el controlador de eventos para verificar el tipo de variable. El tipo solo se establece después de que el usuario selecciona un valor, no cuando la página se carga por primera vez.
self.permissionChanged = function (l) { if (typeof l != 'undefined') { ... } }
Esto parece funcionar para mí.
fuente
utilizar esta:
this.permissionChanged = function (obj, event) { if (event.type != "load") { } }
fuente
Prueba este:
self.GetHierarchyNodeList = function (data, index, event) { debugger; if (event.type != "change") { return; } } event.type == "change" event.type == "load"
fuente
Si está trabajando con Knockout, use la funcionalidad clave de Knockout de funcionalidad observable.
Use el
ko.computed()
método y haga y active la llamada ajax dentro de esa función.fuente