observablearray knockoutjs knockout data knockout.js bindinghandlers

knockout.js - knockoutjs - ko bindinghandlers



Knockoutjs foreach custom bindinghandler con afterAdd (2)

Me gustaría construir un bindingHandler personalizado

ko.bindingHandlers.foreachWithHighlight que tiene un efecto de resaltado cuando afterAdd.

De la documentación

yellowFadeIn: function(element, index, data) { $(element).filter("li") .animate({ backgroundColor: ''yellow'' }, 200) .animate({ backgroundColor: ''white'' }, 800); },

Pero siempre quiero agregar esto a mi valueAccessor y pasarlo al enlace foreach.

ko.bindingHandlers.foreachWithHighlight = { init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) { return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, context); }, update: function (element, valueAccessor, allBindingsAccessor, viewModel, context) { var value = ko.unwrap(valueAccessor()); var newValue = function () { return { data: value, afterAdd: function(element, index, data) { $(element).filter("li") .animate({ backgroundColor: ''yellow'' }, 200) .animate({ backgroundColor: ''white'' }, 800); } }; }; return ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, context); }};

¿Cómo puedo evitar que se ejecute por primera vez cuando se agregan todos los nodos del servidor? Solo quiero que se ejecute cuando se agreguen nuevos nodos.


Si entiendo su escenario correctamente, entonces el problema es que la hora inicial en que rellena su array observable (después del enlace) verá su punto culminante. Una forma de manejar un escenario como este sería usar ko.utils.domData o $.data para poner un indicador en el elemento para indicar que ahora está listo para el efecto de resaltado.

Algo como:

ko.bindingHandlers.foreachWithHighlight = { init: function (element, valueAccessor, allBindingsAccessor, viewModel, context) { return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, context); }, update: function (element, valueAccessor, allBindingsAccessor, viewModel, context) { var value = ko.unwrap(valueAccessor()), key = "forEachWithHightlight_initialized"; var newValue = function () { return { data: value, afterAdd: function (el, index, data) { if (ko.utils.domData.get(element, key)) { $(el).filter("li") .animate({ backgroundColor: ''yellow'' }, 200) .animate({ backgroundColor: ''white'' }, 800); } } }; }; ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, context); //if we have not previously marked this as initialized and there are currently items in the array, then cache on the element that it has been initialized if (!ko.utils.domData.get(element, key) && value.length) { ko.utils.domData.set(element, key, true); } return { controlsDescendantBindings: true }; } };

Fiddle aquí: http://jsfiddle.net/rniemeyer/zGJX3/


Modifiqué uno de los tutoriales knockout, pero no usa un enlace personalizado, pero sigue impulsando el comportamiento a través de beforeRemove y afterAdd que se enganchan en el observableArray.

data-bind=''template: { foreach: planetsToShow, beforeRemove: hidePlanetElement, afterAdd: showPlanetElement }''

Dependiendo de la compatibilidad, podría usar transiciones css3 como lo hice aquí para darle al elemento recién agregado un color amarillo que transiciones al normal después de un tiempo determinado. (Aunque los tiempos y los colorantes que utilicé necesitan trabajo;))

En este violín, parece estar funcionando al no aplicar a la lista original, pero supongo que esto podría deberse a ¿en qué etapa se modifica la Array observable?

http://jsfiddle.net/8k8V5/1529/