2012-07-31 11 views
10

Estoy tratando de especificar un efecto de entrada en los elementos que se insertan utilizando un enlace knockoutjs foreach. configuración muy sencilla:knockoutjs afterRender function for foreach binding

myViewModel.myObservableArray.push({enter:function() { ... }); 

y en el marcado:

foreach:{data:myObservableArray, afterRender:enter} 

parece que debería funcionar ... ¿verdad? Pero no encuentra la función enter en el artículo. Lo que he encontrado funciona es:

myViewModel.enter = function(something, item) { item.enter(); }; 

foreach:{data:myObservableArray, afterRender:$root.enter} 

añadiendo una función de entrar a la vista del modelo de la raíz y la unión afterRender a $ root.enter. Intro pasa luego el elemento como su segundo parámetro, por lo que a su vez puede llamar a la función de entrada del elemento, pero se siente como un truco.

¿Alguien puede explicar lo que está pasando aquí?

Gracias.

EDIT:

Para aclarar He creado un fiddle.

Lo que esto hace es muy simple, y se trata con más profundidad en el animated transitions example. Está ejecutando una función en el modelo de vista raíz para cada elemento dom que se inserta utilizando el enlace foreach.

Entonces, la pregunta es: ¿qué ocurre si deseo que las funciones afterRender, afterAdd o beforeEmove sean específicas del artículo? Pude ver que esto era útil. Especialmente si usa el enlace de plantilla para seleccionar dinámicamente una plantilla (note 4). ¿Hay una manera limpia de hacer esto? En este momento tengo una función enter en la raíz del modelo de vista que simplemente llama a la función enter en el elemento, pero como dije antes, esto parece un truco.

Respuesta

6

No, esta es la manera it was designed.

Desde el Documenation:

Nota 3: El uso de “afterRender”, “afterAdd”, y “beforeRemove”

A veces es posible que desee ejecutar a medida lógica post-procesado de los elementos DOM generados por sus plantillas. Por ejemplo, si está utilizando una biblioteca de widgets JavaScript como jQuery UI, puede interceptar la salida de sus plantillas para que pueda ejecutar comandos de jQuery UI en ella para transformar algunos de los elementos renderizados en selectores de fecha, controles deslizantes o Algo más.

En general, la mejor manera de realizar dicho postproceso en los elementos DOM es escribir un custom binding, pero si realmente solo desea acceder a los elementos de DOM sin procesar emitidos por una plantilla, puede usar afterRender.

Pase una referencia de función (ya sea una función literal, o dé el nombre de una función en su modelo de vista), y Knockout la invocará inmediatamente después de renderizar o volver a representar su plantilla.

(El énfasis es mío)


Como se dice, una unión costumbre es otra manera de hacerlo, y puede ser mejor en función de lo que hace que la función enter().

+1

Copiar y pegar la documentación y responder la pregunta no siempre son lo mismo. Ya había leído los documentos. Aunque sé que no siempre es el caso en este foro, entonces eliminé el voto a favor. Eso fue solo frustración hablando ... – nicholas

+0

@nicholas Lo siento, te frustré, no estaba tratando de disuadir tu pregunta. Traté de hacer más que pegar la documentación, pero la explicación más allá de eso fue bastante simple. Parecía preguntarte por qué se comportaba de esa manera, y la respuesta es: porque fue diseñado para eso. – Tyrsius

+0

Sí, de prisa presioné el botón de abajo antes de pensarlo. Tienes razón, por supuesto. He editado la pregunta para ser más claro. Si lo que estoy tratando de hacer (tener una función personalizada, específica del artículo, afterAdd) no es lo que hace el knockout por defecto, entonces la pregunta es: ¿cómo hago que haga lo que quiero? ¿Hay algún truco que no esté viendo? ¿O una pieza de código flotando por ahí que podría usar? Realmente no quiero perder un día reconstruyendo el enlace foreach si alguien ya ha hecho el trabajo por mí ... – nicholas

5

subrayado rebote (_.debounce) es una gran solución en tal caso.

plantilla

data-bind=" template: {foreach:myObservableArray, afterRender: runWhenAllRenderDone } 

retardo de entrada se ejecutará si afterRender no se dispara en el pasado 100 milisegundo.

var runWhenAllRenderDone = _.debounce(myFunction, 100); 

function myFunction(){ 
    //do some task but do it for once only 
} 

is't it awesome?

+0

Eso debería ser Underscore rebote, no Backbone. – LocalPCGuy

+0

+1 En mi caso, no puedo usar 'afterRender' para asegurarme de que el engin de knockout haya terminado de renderizar html porque he encapsulado la lógica de la función que cambia los elementos en el observableArray; código no es accesible desde el html. Sé que no es elegante, pero también uso un tiempo de espera de x milisegundos antes de llamar a otra función que está agregando css a los nuevos nodos de elementos. De hecho, acabo de establecer un tiempo de espera de 1 milisegundo y después de actualizar mi página docenas de veces, no veo ningún caso cuando mi html no se actualiza correctamente. Gracias. – Samuel