Właśnie otrzymałem dyrektywę, aby pobrać szablon, aby dołączyć do jego elementu w następujący sposób:
# 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>
Używam również wtyczki jQuery o nazwie DataTables. Jego ogólne użycie jest takie: $ ('table # some_id'). DataTable (). Możesz przekazać dane JSON do wywołania dataTable (), aby dostarczyć dane tabeli LUB możesz mieć dane już na stronie i zrobi resztę .. Robię to drugie, mając wiersze już na stronie HTML .
Ale problem polega na tym, że muszę wywołać funkcję dataTable () w tabeli # line_items PO gotowym DOM. Moja dyrektywa powyżej wywołuje metodę dataTable () ZANIM szablon zostanie dołączony do elementu dyrektywy. Czy istnieje sposób, w jaki mogę wywoływać funkcje PO dołączeniu?
Dziękuję za pomoc!
UPDATE 1 po odpowiedzi Andy'ego:
Chcę się upewnić, że metoda linku zostanie wywołana tylko PO tym, jak wszystko jest na stronie, więc zmieniłem dyrektywę na krótki test:
# 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>"
}
I rzeczywiście widzę „boo” w div # sayboo.
Następnie próbuję wywołać 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') %>"
}
Nie ma szczęścia
Następnie próbuję dodać limit czasu:
.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') %>"
}
I to działa. Więc zastanawiam się, co poszło nie tak w wersji kodu bez timera?
Odpowiedzi:
Jeśli drugi parametr „opóźnienie” nie zostanie podany, domyślnym zachowaniem jest wykonanie funkcji po zakończeniu renderowania modelu DOM. Więc zamiast setTimeout użyj $ timeout:
źródło
$timeout(fn)
ostatecznie wywołania,setTimeout(fn, 0)
które powodują przerwanie wykonywania Javascript i pozwolenie przeglądarce na renderowanie treści w pierwszej kolejności, przed kontynuowaniem wykonywania tego Javascript.Miałem ten sam problem i uważam, że odpowiedź brzmi „nie”. Zobacz komentarz Miško i dyskusję w grupie .
Angular może śledzić, że wszystkie wywołania funkcji, które wykonuje w celu manipulowania DOM, są kompletne, ale ponieważ te funkcje mogą wyzwalać logikę asynchroniczną, która nadal aktualizuje DOM po ich powrocie, nie można było oczekiwać, że będzie o tym wiedział. Każde wywołanie zwrotne, które daje Angular, może czasami działać, ale nie można by na nim polegać.
Rozwiązaliśmy to heurystycznie za pomocą setTimeout, tak jak Ty.
(Pamiętaj, że nie wszyscy się ze mną zgadzają - przeczytaj komentarze pod powyższymi linkami i zobacz, co myślisz.)
źródło
Możesz skorzystać z funkcji „link”, znanej również jako postLink, która jest uruchamiana po wstawieniu szablonu.
Przeczytaj, jeśli planujesz tworzyć dyrektywy, to duża pomoc: http://docs.angularjs.org/guide/directive
źródło
Chociaż moja odpowiedź nie jest związana z danymi, to dotyczy problemu manipulacji DOM i np. Inicjalizacji wtyczki jQuery dla dyrektyw używanych na elementach, których zawartość jest aktualizowana w sposób asynchroniczny.
Zamiast implementować limit czasu, można po prostu dodać zegarek, który będzie nasłuchiwał zmian treści (lub nawet dodatkowych zewnętrznych wyzwalaczy).
W moim przypadku użyłem tego obejścia do zainicjowania wtyczki jQuery po wykonaniu ng-repeat, które utworzyło mój wewnętrzny DOM - w innym przypadku użyłem go tylko do manipulowania DOM po zmianie właściwości scope na kontrolerze. Oto jak to zrobiłem ...
HTML:
JS:
Uwaga: Zamiast po prostu rzutować zmienną myContent na wartość bool w atrybucie my-Directive-watch, można sobie wyobrazić dowolne wyrażenie.
Uwaga: Izolowanie zakresu, jak w powyższym przykładzie, można wykonać tylko raz na element - próba zrobienia tego z wieloma dyrektywami na tym samym elemencie spowoduje $ compile: multidir Error - patrz: https://docs.angularjs.org / error / $ compile / multidir
źródło
Może spóźnię się na odpowiedź na to pytanie. Ale nadal ktoś może skorzystać z mojej odpowiedzi.
Miałem podobny problem iw moim przypadku nie mogę zmienić dyrektywy, ponieważ jest to biblioteka i zmiana kodu biblioteki nie jest dobrą praktyką. Więc użyłem zmiennej, aby poczekać na załadowanie strony i użyć ng-if w moim html, aby czekać, wyrenderować określony element.
W moim kontrolerze:
W moim html (w moim przypadku komponent html to płótno)
źródło
Miałem ten sam problem, ale używając Angular + DataTable z
fnDrawCallback
+ grupowaniem wierszy + $ skompilowanymi zagnieżdżonymi dyrektywami. Umieściłem $ timeout w moimfnDrawCallback
funkcji, aby naprawić renderowanie stronicowania.Przed przykładem, na podstawie źródła row_grouping:
Po przykładzie:
Nawet krótkie opóźnienie wystarczyło, aby Angular mógł wyrenderować moje skompilowane dyrektywy Angulara.
źródło
Żadne z rozwiązań nie działało dla mnie, nie zgadzam się z użyciem limitu czasu. Dzieje się tak, ponieważ korzystałem z szablonu, który był dynamicznie tworzony podczas postLink.
Należy jednak pamiętać, że może wystąpić przekroczenie limitu czasu „0”, ponieważ limit czasu powoduje dodanie wywoływanej funkcji do kolejki przeglądarki, która nastąpi po silniku renderowania kątowego, ponieważ znajduje się on już w kolejce.
Zobacz to: http://blog.brunoscopelliti.com/run-a-directive-after-the-dom-has-finished-rendering
źródło
Oto dyrektywa, która ma zaprogramować akcje po płytkim renderowaniu. Przez płytkie mam na myśli, że oceni on po wyrenderowaniu tego samego elementu i nie będzie to miało związku z tym, kiedy jego zawartość zostanie renderowana. Więc jeśli potrzebujesz jakiegoś elementu podrzędnego wykonującego akcję po renderowaniu, powinieneś rozważyć użycie go tam:
wtedy możesz:
<div after-render></div>
lub z jakimkolwiek przydatnym wyrażeniem, takim jak:
<div after-render="$emit='onAfterThisConcreteThingRendered'"></div>
źródło
Mam to działając z następującą dyrektywą:
A w HTML:
rozwiązywanie problemów, jeśli powyższe nie działa.
1) zauważ, że „datatableSetup” jest odpowiednikiem „datatable-setup”. Angular zmienia format na kopertę wielbłąda.
2) upewnij się, że aplikacja jest zdefiniowana przed dyrektywą. np. prosta definicja i dyrektywa aplikacji.
źródło
Ponieważ nie można przewidzieć kolejności załadunku, można zastosować proste rozwiązanie.
Przyjrzyjmy się relacji dyrektywa-„użytkownik dyrektywy”. Zwykle użytkownik dyrektywy dostarczy pewne dane do dyrektywy lub użyje pewnych funkcji (funkcji), które zapewnia dyrektywa. Z drugiej strony dyrektywa wymaga określenia niektórych zmiennych dotyczących jej zakresu.
Jeśli uda nam się upewnić, że wszyscy gracze spełnili wszystkie wymagania dotyczące akcji, zanim podejmą próbę wykonania tych czynności - wszystko powinno być w porządku.
A teraz dyrektywa:
a teraz użytkownik dyrektywy html
i gdzieś w kontrolerze komponentu, który używa dyrektywy:
O to chodzi. Jest dużo narzutów, ale możesz stracić limit czasu $. Zakładamy również, że komponent, który używa dyrektywy, jest tworzony przed dyrektywą, ponieważ zależymy od zmiennej kontrolnej, aby istniała podczas tworzenia wystąpienia dyrektywy.
źródło