tipos ejemplos directivas angular1 angularjs

angularjs - directivas - ng if ejemplos



¿hay una devolución de llamada posterior para la directiva Angular JS? (10)

Acabo de recibir mi directiva para obtener una plantilla para agregar 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 esto es así: $ (''table # some_id''). DataTable (). Puede pasar los datos JSON a la llamada dataTable () para suministrar 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 anexe al elemento de la directiva. ¿Hay alguna manera de llamar funciones DESPUÉS de agregar?

¡Gracias por tu ayuda!

ACTUALIZAR 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 realmente 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 allí

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é va mal en la versión del código que no es de temporizador.


Aquí hay una directiva para tener acciones programadas después de una renderización superficial. Por superficial quiero decir que evaluará después de que se haya prestado ese mismo elemento y que no estará relacionado con cuándo se procesa su contenido. Por lo tanto, si necesita algún sub elemento haciendo una acción de renderización posterior, debería considerar usarlo allí:

define([''angular''], function (angular) { ''use strict''; return angular.module(''app.common.after-render'', []) .directive(''afterRender'', [ ''$timeout'', function($timeout) { var def = { restrict : ''A'', terminal : true, transclude : false, link : function(scope, element, attrs) { if (attrs) { scope.$eval(attrs.afterRender) } scope.$emit(''onAfterRender'') } }; return def; }]); });

entonces puedes hacer:

<div after-render></div>

o con cualquier expresión útil como:

<div after-render="$emit=''onAfterThisConcreteThingRendered''"></div>


Aunque mi respuesta no está relacionada con las tablas de datos, aborda el problema de la manipulación de DOM y, por ejemplo, la inicialización de jQuery plugin para directivas utilizadas en elementos que tienen sus contenidos actualizados de manera asíncrona.

En lugar de implementar un tiempo de espera uno podría simplemente agregar un reloj que escuchará los cambios de contenido (o incluso desencadenantes externos adicionales).

En mi caso utilicé esta solución alternativa para inicializar un plugin 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 alteró en el controlador. Así es como lo hice ...

HTML:

<div my-directive my-directive-watch="!!myContent">{{myContent}}</div>

JS:

app.directive(''myDirective'', [ function(){ return { restrict : ''A'', scope : { myDirectiveWatch : ''='' }, compile : function(){ return { post : function(scope, element, attributes){ scope.$watch(''myDirectiveWatch'', function(newVal, oldVal){ if (newVal !== oldVal) { // Do stuff ... } }); } } } } }]);

Nota: En lugar de simplemente enviar la variable myContent a bool en el atributo my-directive-watch, uno podría imaginar cualquier expresión arbitraria allí.

Nota: Aislar el alcance como en el ejemplo anterior solo se puede hacer una vez por elemento. Intentar hacer esto con varias directivas en el mismo elemento dará como resultado una compilación $: error multidir - ver: https://docs.angularjs.org/error/$compile/multidir


Lo hice trabajando con la siguiente directiva:

app.directive(''datatableSetup'', function () { return { link: function (scope, elm, attrs) { elm.dataTable(); } } });

Y en el HTML:

<table class="table table-hover dataTable dataTable-columnfilter " datatable-setup="">

solució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 en camel case.

2) asegúrese de que la aplicación esté definida antes de la directiva. por ejemplo, definición y directiva de aplicación simple.

var app = angular.module(''app'', []); app.directive(''datatableSetup'', function () { return { link: function (scope, elm, attrs) { elm.dataTable(); } } });


Ninguna de las soluciones funcionó para mí aceptar el uso de un tiempo de espera. Esto se debe a que estaba usando una plantilla que se creaba 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 ocurrirá después del motor de representación angular ya que este ya está en la cola.

Consulte esto: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering


Puede ser tarde para responder esta pregunta. Pero aún así, alguien puede obtener beneficio 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-si dentro de mi html para esperar renderizar el elemento en particular.

En mi controlador:

$scope.render=false; //this will fire after load the the page angular.element(document).ready(function() { $scope.render=true; });

En mi html (en mi caso, el componente html es un lienzo)

<canvas ng-if="render"> </canvas>


Puede usar la función ''enlace'', también conocida como postLink, que se ejecuta después de colocar la plantilla.

app.directive(''myDirective'', function() { return { link: function(scope, elm, attrs) { /*I run after template is put in */ }, template: ''<b>Hello</b>'' } });

Dale una lectura si planeas hacer directivas, es una gran ayuda: http://docs.angularjs.org/guide/directive


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, usa $ timeout:

$timeout(function () { //DOM has finished rendering });


Siguiendo el hecho de que no se puede anticipar el orden de carga, se puede usar 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á algunas funcionalidades (funciones) que la directiva suministra. La directiva, por otro lado, espera que se definan algunas variables 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:

app.directive(''aDirective'', function () { return { scope: { input: ''='', control: ''='' }, link: function (scope, element) { function functionThatNeedsInput(){ //use scope.input here } if ( scope.input){ //We already have input functionThatNeedsInput(); } else { scope.control.init = functionThatNeedsInput; } } }; })

y ahora el usuario de la directiva html

<a-directive control="control" input="input"></a-directive>

y en algún lugar del controlador del componente que usa la directiva:

$scope.control = {}; ... $scope.input = ''some data could be async''; if ( $scope.control.functionThatNeedsInput){ $scope.control.functionThatNeedsInput(); }

Eso es todo. Hay una gran cantidad de gastos generales, pero puede perder $ timeout. También suponemos que el componente que usa la directiva se instancia antes de la directiva porque dependemos de la variable de control que existe cuando se crea una instancia de la directiva.


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 su retorno, no se podría esperar que Angular lo supiera. Cualquier devolución de llamada angular podría funcionar a veces, pero no sería seguro confiar.

Solucionamos esto heurísticamente con un setTimeout, como lo hiciste tú.

(Tenga en cuenta que no todos están de acuerdo conmigo, debe leer los comentarios en los enlaces anteriores y ver lo que piensa).


Tuve el mismo problema, pero usando Angular + DataTable con un fnDrawCallback + agrupación de filas + $ compiled anidados directivas. Puse el $ timeout en mi función fnDrawCallback para corregir la representación de paginación.

Antes del ejemplo, basado en la fuente row_grouping:

var myDrawCallback = function myDrawCallbackFn(oSettings){ var nTrs = $(''table#result>tbody>tr''); for(var i=0; i<nTrs.length; i++){ //1. group rows per row_grouping example //2. $compile html templates to hook datatable into Angular lifecycle } }

Después del ejemplo:

var myDrawCallback = function myDrawCallbackFn(oSettings){ var nTrs = $(''table#result>tbody>tr''); $timeout(function requiredRenderTimeoutDelay(){ for(var i=0; i<nTrs.length; i++){ //1. group rows per row_grouping example //2. $compile html templates to hook datatable into Angular lifecycle } ,50); //end $timeout }

Incluso un breve tiempo de espera fue suficiente para permitir a Angular presentar mis directivas angulares compiladas.