Ich habe gerade meine Anweisung erhalten, eine Vorlage einzufügen, um sie wie folgt an ihr Element anzuhängen:
# 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>
Ich verwende auch ein jQuery-Plugin namens DataTables. Die allgemeine Verwendung lautet wie folgt: $ ('table # some_id'). DataTable (). Sie können die JSON-Daten an den Aufruf dataTable () übergeben, um die Tabellendaten bereitzustellen, ODER Sie können die Daten bereits auf der Seite haben und den Rest erledigen. Letzteres mache ich, da die Zeilen bereits auf der HTML-Seite sind .
Das Problem ist jedoch, dass ich die dataTable () in der Tabelle # line_items AFTER DOM ready aufrufen muss. Meine obige Direktive ruft die dataTable () -Methode auf, BEVOR die Vorlage an das Element der Direktive angehängt wird. Gibt es eine Möglichkeit, Funktionen nach dem Anhängen aufzurufen?
Danke für Ihre Hilfe!
UPDATE 1 nach Andys Antwort:
Ich möchte sicherstellen, dass die Link-Methode erst aufgerufen wird, nachdem sich alles auf der Seite befindet. Deshalb habe ich die Direktive für einen kleinen Test geändert:
# 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>"
}
Und ich sehe tatsächlich "boo" im div # sayboo.
Dann versuche ich meinen jquery datatable Anruf
.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') %>"
}
Kein Glück da
Dann versuche ich eine Auszeit hinzuzufügen:
.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') %>"
}
Und das funktioniert. Ich frage mich also, was in der Nicht-Timer-Version des Codes schief geht.
Antworten:
Wenn der zweite Parameter "Verzögerung" nicht angegeben ist, wird die Funktion standardmäßig ausgeführt, nachdem das DOM das Rendern abgeschlossen hat. Verwenden Sie also anstelle von setTimeout $ timeout:
quelle
$timeout(fn)
Letztendlich werden Aufrufe ausgeführt,setTimeout(fn, 0)
wodurch die Ausführung von Javascript unterbrochen wird und der Browser den Inhalt zuerst rendern kann, bevor die Ausführung dieses Javascript fortgesetzt wird.Ich hatte das gleiche Problem und ich glaube, die Antwort ist wirklich nein. Siehe Miškos Kommentar und einige Diskussionen in der Gruppe .
Angular kann nachverfolgen, dass alle Funktionsaufrufe zur Manipulation des DOM abgeschlossen sind. Da diese Funktionen jedoch eine asynchrone Logik auslösen können, die das DOM nach ihrer Rückkehr immer noch aktualisiert, kann nicht erwartet werden, dass Angular davon erfährt. Jeder Rückruf Angular gibt vielleicht arbeitet manchmal, aber nicht sicher sein zu vertrauen.
Wir haben dies heuristisch mit einem setTimeout gelöst, wie Sie es getan haben.
(Bitte denken Sie daran, dass nicht jeder mit mir einverstanden ist - Sie sollten die Kommentare zu den obigen Links lesen und sehen, was Sie denken.)
quelle
Sie können die 'Link'-Funktion verwenden, die auch als postLink bezeichnet wird und nach dem Einfügen der Vorlage ausgeführt wird.
Lesen Sie dies, wenn Sie Richtlinien erstellen möchten. Dies ist eine große Hilfe: http://docs.angularjs.org/guide/directive
quelle
Obwohl sich meine Antwort nicht auf Datentabellen bezieht, befasst sie sich mit dem Problem der DOM-Manipulation und z. B. der Initialisierung des jQuery-Plugins für Anweisungen, die für Elemente verwendet werden, deren Inhalt asynchron aktualisiert wurde.
Anstatt eine Zeitüberschreitung zu implementieren, könnte man einfach eine Uhr hinzufügen, die Inhaltsänderungen (oder sogar zusätzliche externe Auslöser) abhört.
In meinem Fall habe ich diese Problemumgehung zum Initialisieren eines jQuery-Plugins verwendet, nachdem die ng-Wiederholung durchgeführt wurde, wodurch mein inneres DOM erstellt wurde. In einem anderen Fall habe ich es nur zum Bearbeiten des DOM verwendet, nachdem die Eigenschaft scope am Controller geändert wurde. So habe ich es gemacht ...
HTML:
JS:
Hinweis: Anstatt nur die Variable myContent mit dem Attribut my-directive-watch in bool umzuwandeln, könnte man sich dort einen beliebigen Ausdruck vorstellen.
Hinweis: Das Isolieren des Bereichs wie im obigen Beispiel kann nur einmal pro Element durchgeführt werden. Wenn Sie dies mit mehreren Anweisungen für dasselbe Element tun, wird ein $ compile: multidir-Fehler angezeigt - siehe: https://docs.angularjs.org / error / $ compile / multidir
quelle
Möglicherweise bin ich zu spät, um diese Frage zu beantworten. Trotzdem kann jemand von meiner Antwort profitieren.
Ich hatte ein ähnliches Problem und in meinem Fall kann ich die Direktive nicht ändern, da es sich um eine Bibliothek handelt und das Ändern eines Codes der Bibliothek keine gute Praxis ist. Also habe ich eine Variable verwendet, um auf das Laden der Seite zu warten, und ng-if in meinem HTML-Code verwendet, um auf das Rendern des jeweiligen Elements zu warten.
In meinem Controller:
In meinem HTML (in meinem Fall ist die HTML-Komponente eine Zeichenfläche)
quelle
Ich hatte das gleiche Problem, aber ich verwendete Angular + DataTable mit einer
fnDrawCallback
+ Zeilengruppierung + $ kompilierten verschachtelten Anweisungen. Ich habe das $ timeout in meinefnDrawCallback
Funktion eingefügt, um das Paginierungs-Rendering zu korrigieren.Vorheriges Beispiel, basierend auf der Quelle row_grouping:
Nach dem Beispiel:
Schon eine kurze Timeout-Verzögerung reichte aus, um Angular das Rendern meiner kompilierten Angular-Direktiven zu ermöglichen.
quelle
Keine der für mich funktionierenden Lösungen akzeptiert die Verwendung eines Timeouts. Dies liegt daran, dass ich eine Vorlage verwendet habe, die während des postLink dynamisch erstellt wurde.
Beachten Sie jedoch, dass es eine Zeitüberschreitung von '0' geben kann, da die Zeitüberschreitung die aufgerufene Funktion zur Warteschlange des Browsers hinzufügt, die nach der Winkel-Rendering-Engine auftritt, da sich diese bereits in der Warteschlange befindet.
Siehe hierzu: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering
quelle
Hier ist eine Anweisung, Aktionen nach einem flachen Render programmieren zu lassen. Mit flach meine ich, dass es nach genau diesem gerenderten Element ausgewertet wird und dass es nichts damit zu tun hat, wann sein Inhalt gerendert wird. Wenn Sie also ein Unterelement benötigen, das eine Post-Rendering-Aktion ausführt, sollten Sie es dort verwenden:
dann können Sie tun:
<div after-render></div>
oder mit einem nützlichen Ausdruck wie:
<div after-render="$emit='onAfterThisConcreteThingRendered'"></div>
quelle
Ich habe dies mit der folgenden Direktive zum Laufen gebracht:
Und im HTML:
Fehlerbehebung, wenn das oben genannte für Sie nicht funktioniert.
1) Beachten Sie, dass 'datatableSetup' dem 'datatable-setup' entspricht. Angular ändert das Format in Kameletui.
2) Stellen Sie sicher, dass die App vor der Direktive definiert ist. zB einfache App Definition und Direktive.
quelle
Da die Ladereihenfolge nicht vorhersehbar ist, kann eine einfache Lösung verwendet werden.
Schauen wir uns die Beziehung zwischen Richtlinie und Benutzer der Richtlinie an. Normalerweise liefert der Benutzer der Direktive einige Daten an die Direktive oder verwendet einige Funktionen, die die Direktive bereitstellt. Die Richtlinie erwartet andererseits, dass einige Variablen in ihrem Geltungsbereich definiert werden.
Wenn wir sicherstellen können, dass alle Spieler alle ihre Aktionsanforderungen erfüllt haben, bevor sie versuchen, diese Aktionen auszuführen, sollte alles in Ordnung sein.
Und jetzt die Richtlinie:
und jetzt der Benutzer der Direktive HTML
und irgendwo in der Steuerung der Komponente, die die Direktive verwendet:
Das ist alles. Es gibt viel Overhead, aber Sie können das $ Timeout verlieren. Wir gehen auch davon aus, dass die Komponente, die die Direktive verwendet, vor der Direktive instanziiert wird, da wir von der Steuervariablen abhängen, die bei der Instanziierung der Direktive vorhanden ist.
quelle