Acabo de recibir mi directiva para extraer una plantilla para agregarla a su elemento de esta manera:
# CoffeeScript
.directive 'dashboardTable', ->
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
(scope, element, attrs) ->
element.parent('table#line_items').dataTable()
console.log 'Just to make sure this is run'
# HTML
<table id="line_items">
<tbody dashboard-table>
</tbody>
</table>
También estoy usando un complemento jQuery llamado DataTables. El uso general de este es el siguiente: $ ('table # some_id'). DataTable (). Puede pasar los datos JSON a la llamada dataTable () para proporcionar los datos de la tabla O puede tener los datos ya en la página y hará el resto ... Estoy haciendo lo último, teniendo las filas ya en la página HTML .
Pero el problema es que tengo que llamar a dataTable () en la tabla # line_items AFTER DOM ready. Mi directiva anterior llama al método dataTable () ANTES de que la plantilla se agregue al elemento de la directiva. ¿Hay alguna manera de que pueda llamar a las funciones DESPUÉS de la adición?
¡Gracias por tu ayuda!
ACTUALIZACIÓN 1 después de la respuesta de Andy:
Quiero asegurarme de que el método de enlace solo se llame DESPUÉS de que todo esté en la página, así que modifiqué la directiva para una pequeña prueba:
# CoffeeScript
#angular.module(...)
.directive 'dashboardTable', ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
element.find('#sayboo').html('boo')
controller: lineItemIndexCtrl
template: "<div id='sayboo'></div>"
}
Y de hecho veo "boo" en el div # sayboo.
Luego pruebo mi llamada jquery datatable
.directive 'dashboardTable', ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
element.parent('table').dataTable() # NEW LINE
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
No hay suerte
Luego trato de agregar un tiempo de espera:
.directive 'dashboardTable', ($timeout) ->
{
link: (scope,element,attrs) ->
console.log 'Just to make sure this gets run'
$timeout -> # NEW LINE
element.parent('table').dataTable()
,5000
controller: lineItemIndexCtrl
templateUrl: "<%= asset_path('angular/templates/line_items/dashboard_rows.html') %>"
}
Y eso funciona. ¿Entonces me pregunto qué sale mal en la versión sin código del temporizador?
Respuestas:
Si no se proporciona el segundo parámetro, "retraso", el comportamiento predeterminado es ejecutar la función después de que el DOM haya completado la representación. Entonces, en lugar de setTimeout, use $ timeout:
fuente
$timeout(fn)
finalmente llama, losetTimeout(fn, 0)
que tiene el efecto de interrumpir la ejecución de Javascript y permitir que el navegador muestre primero el contenido, antes de continuar la ejecución de ese Javascript.Tuve el mismo problema y creo que la respuesta es realmente no. Vea el comentario de Miško y alguna discusión en el grupo .
Angular puede rastrear que todas las llamadas a funciones que realiza para manipular el DOM están completas, pero dado que esas funciones podrían desencadenar una lógica asíncrona que todavía está actualizando el DOM después de que regresen, no se puede esperar que Angular lo sepa. Cualquier devolución de llamada Angular puede funcionar a veces, pero no sería seguro confiar en ella.
Resolvimos esto heurísticamente con un setTimeout, como lo hiciste.
(Tenga en cuenta que no todos están de acuerdo conmigo, debe leer los comentarios en los enlaces anteriores y ver lo que piensa).
fuente
Puede usar la función 'enlace', también conocida como postLink, que se ejecuta después de colocar la plantilla.
Lea esto si planea hacer directivas, es de gran ayuda: http://docs.angularjs.org/guide/directive
fuente
Aunque mi respuesta no está relacionada con las tablas de datos, aborda el problema de la manipulación del DOM y, por ejemplo, la inicialización del complemento jQuery para directivas utilizadas en elementos que tienen sus contenidos actualizados de manera asíncrona.
En lugar de implementar un tiempo de espera, se podría agregar un reloj que escuchará los cambios de contenido (o incluso desencadenantes externos adicionales).
En mi caso, utilicé esta solución para inicializar un complemento jQuery una vez que se realizó la repetición ng que creó mi DOM interno; en otro caso, lo usé solo para manipular el DOM después de que la propiedad del alcance se modificó en el controlador. Así es como lo hice ...
HTML:
JS:
Nota: en lugar de simplemente convertir la variable myContent en bool en el atributo my-directive-watch, uno podría imaginar cualquier expresión arbitraria allí.
Nota: El aislamiento del alcance como en el ejemplo anterior solo se puede hacer una vez por elemento; si se intenta hacer esto con varias directivas sobre el mismo elemento, se generará $ compile: multidir Error: consulte: https://docs.angularjs.org / error / $ compile / multidir
fuente
Puede que llegue tarde para responder esta pregunta. Pero aún así alguien puede obtener beneficios de mi respuesta.
Tuve un problema similar y en mi caso no puedo cambiar la directiva, ya que es una biblioteca y cambiar un código de la biblioteca no es una buena práctica. Entonces, lo que hice fue usar una variable para esperar la carga de la página y usar ng-if dentro de mi html para esperar renderizar el elemento en particular.
En mi controlador:
En mi html (en mi caso, el componente html es un lienzo)
fuente
Tuve el mismo problema, pero usando Angular + DataTable con una
fnDrawCallback
+ agrupación de filas + $ directivas anidadas compiladas. Puse el $ timeout en mifnDrawCallback
función para corregir la representación de paginación.Antes del ejemplo, basado en la fuente row_grouping:
Después del ejemplo:
Incluso un breve retraso de tiempo de espera fue suficiente para permitir que Angular procese mis directivas angulares compiladas.
fuente
Ninguna de las soluciones que funcionó para mí acepta el uso de un tiempo de espera. Esto se debe a que estaba usando una plantilla que se estaba creando dinámicamente durante el postLink.
Sin embargo, tenga en cuenta que puede haber un tiempo de espera de '0' ya que el tiempo de espera agrega la función que se llama a la cola del navegador que se producirá después del motor de representación angular, ya que esto ya está en la cola.
Consulte esto: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering
fuente
Aquí hay una directiva para tener acciones programadas después de un render superficial. Por superficial quiero decir que evaluará después de ese elemento renderizado y que no estará relacionado con cuándo se representará su contenido. Entonces, si necesita algún subelemento que realice una acción de renderizado posterior, debería considerar usarlo allí:
entonces puedes hacer:
<div after-render></div>
o con cualquier expresión útil como:
<div after-render="$emit='onAfterThisConcreteThingRendered'"></div>
fuente
Obtuve esto trabajando con la siguiente directiva:
Y en el HTML:
resolución de problemas si lo anterior no funciona para usted.
1) tenga en cuenta que 'datatableSetup' es el equivalente de 'datatable-setup'. Angular cambia el formato a camello.
2) asegúrese de que la aplicación esté definida antes de la directiva. por ejemplo, definición y directiva de aplicación simple.
fuente
Siguiendo el hecho de que no se puede anticipar el orden de carga, se puede utilizar una solución simple.
Veamos la relación directiva-usuario de la directiva. Por lo general, el usuario de la directiva proporcionará algunos datos a la directiva o utilizará alguna funcionalidad (funciones) que proporciona la directiva. La directiva, por otro lado, espera que algunas variables se definan en su alcance.
Si podemos asegurarnos de que todos los jugadores cumplan con todos sus requisitos de acción antes de intentar ejecutar esas acciones, todo debería estar bien.
Y ahora la directiva:
y ahora el usuario de la directiva html
y en algún lugar del controlador del componente que usa la directiva:
Eso es todo. Hay muchos gastos generales, pero puede perder el tiempo de espera $. También suponemos que el componente que usa la directiva se instancia antes de la directiva porque dependemos de la variable de control que exista cuando se instancia la directiva.
fuente