$ postLink komponentu/dyrektywy kątowej uruchomiono zbyt wcześnie



Aktualizacja:

Przydzieliłem nagrodę za to pytanie. Nie szukam hacków ani obejść. Szukam oficjalnego sposobu na dostęp do domeny w komponencie kątowym i wyjaśnienie, dlaczego zachowanie, które widzę ($ postLink działa przed rozpoczęciem) wydaje się być sprzeczne z oficjalną dokumentacją.

Oficjalne dokumenty określają (

tutaj
https://docs.angularjs.org/guide/component
):

$ postLink () - wywoływana po połączeniu tego elementu kontrolera i jego elementów podrzędnych. Podobnie jak funkcja post-link, ten punkt zaczepienia może być używany do konfigurowania procedur obsługi zdarzeń DOM i wykonywania bezpośrednich manipulacji DOM


Oryginalne pytanie:

Mam tutaj przykład problemu - & >

http://plnkr.co/edit/rMm9FOwIm ... eview
http://plnkr.co/edit/rMm9FOwIm ... eview
Używam komponentu kątowego i chcę zmienić dom w funkcji łącza posta, ale to nie działa, wygląda na to, że funkcja działa zbyt wcześnie, zanim szablon będzie faktycznie gotowy w dom po całym przetwarzaniu kątowym.
Na stronie html mam to:
<my-grid grid-id="'foo'"></my-grid>

Składnik definiuje się jako:
appModule.component('myGrid',{
controller: gridController,
bindings: {
"gridId": "<",
},
templateUrl: 'gridTemplate'
});

W moim szablonie komponentów mam to:
<table id='{{$ctrl.gridId}}'>...

(Sam wiążący działa, nie ma wątpliwości co do tego. W końcu, w HTML, identyfikator tabeli jest "foo", zgodnie z oczekiwaniami).
W moim kontrolerze mam coś takiego:
function gridController($scope, $compile, $attrs) {
console.log ("grid id is: " + this.gridId);// 'foo' this.$postLink = function() {
var elem = document.getElementById(this.gridId);
// do something with elem, but elem is null
}
}

Podczas debugowania widzę, że po wykonaniu funkcji $ postLink tabela znajduje się w domenie, ale jej atrybut id nadal ma wartość
{{$ ctrl.gridId}}
zamiast
foo
, więc
document.getElementById ()
niczego nie znajduje. Wydaje się, że jest to sprzeczne z dokumentacją.

czego mi brakuje? Czy istnieje inny sposób uzyskania dostępu do domeny w komponencie? [/code]
Aktualizacja 2:

Dzisiaj zdałem sobie sprawę, że ten sam problem występuje z normalną funkcją linku dyrektywy, nie jest on ograniczony do komponentów. Najwyraźniej źle zrozumiałem znaczenie „bezpośredniej manipulacji DOM” - funkcja link działa na elemencie oddzielnym od domeny, więc używanie obiektu
document
z selektorami jest bezużyteczne.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Nieporozumienie polega na tym, jak kątowa pętla $ Digest działa w połączeniu ze zdarzeniami cyklu życia kontrolera (i zdarzeniami cyklu życia dyrektywy).
Każde zdarzenie cyklu życia kontrolera/dyrektywy jest wywoływane wewnątrz $ apply, więc DOM jest aktualizowany tylko w celu odzwierciedlenia późniejszych zmian

koniec cyklu
https://docs.angularjs.org/gui ... -loop
$digest .
Funkcja linku do posta jest uruchamiana po połączeniu wszystkiego, ale dokładnie

na końcu tej funkcji
http://odetocode.com/blogs/sco ... .aspx
DOM jest aktualizowany w celu odzwierciedlenia wszelkich powiązań, ponieważ jest to ostatnia funkcja uruchamiana wewnątrz pętli $ digest. Oznacza to, że próba wysłania zapytania do DOM o cokolwiek, na co ma wpływ powiązanie, nie zadziała (np.
ng-repeat
lub, w twoim przypadku, wartość związana). Ale jak mówią dokumenty, powiązanie DOM już działa, więc oryginalny szablon jest tworzony i można go modyfikować.
Ponieważ musisz zażądać DOM po zastosowaniu Bindings, musisz uruchomić kod po zakończeniu bieżącego cyklu $ digest. Oznacza to używanie
$ timeout
z opóźnieniem 0, co spowoduje

wykonywane natychmiast po zakończeniu bieżącego cyklu
http://blog.brunoscopelliti.co ... ring/
$digest .
function gridController($scope, $compile, $attrs, $timeout) {
console.log ("grid id is: " + this.gridId);// 'foo' this.$postLink = function() {
$timeout(function() {
var elem = document.getElementById(this.gridId);
// do something with elem now that the DOM has had it's bindings applied
});
}
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Wydaje się, że ma to coś wspólnego ze zrozumieniem skryptów komponentu kątowego przed podaniem jakiegokolwiek rozwiązania. I co widzę na twoim przykładzie, szablon DOM jest załadowany

odosobniony

region. Powtarzam

jednostka

Tom
Więc,

Zgodnie z oficjalnym dokumentem [1.5.6] dotyczącym komponentów

https://docs.angularjs.org/guide/component
https://docs.angularjs.org/guide/component
Kiedy nie używać komponentów

:
  • dla dyrektyw, które opierają się na manipulacji DOM, dodawaniu detektorów zdarzeń itp., ponieważ funkcje kompilacji i łączenia nie są dostępne
  • gdy potrzebujesz zaawansowanych opcji definicji dyrektyw, takich jak priorytet, terminal, wieloelementowa
  • jeśli potrzebujesz dyrektywy, która jest wyzwalana przez atrybut lub klasę CSS, a nie element
Jeśli spojrzysz na porównanie między definicją dyrektywy a sekcją dotyczącą definicji komponentu w dokumencie, zobaczysz

  • feature------------directive-----------component
  • wiązania ------------ Nie ------------------- Tak (wiąże się z kontrolerem)
  • bindToController ---- tak (domyślnie: false) - nie (zamiast tego użyj powiązań)
  • Zrób funkcję ---- Tak ------------------ Nie
  • kontroler ---------- Tak ------------------ Tak (funkcja domyślna () {})
  • kontrolerAs -------- tak ------------------ (domyślnie: false) Tak (domyślnie: $ ctrl)
  • funkcje linków ------ Tak ------------------ Nie

Teraz

Komponenty nigdy nie powinny modyfikować żadnych danych ani DOM poza nimi
posiadać

obszary

działania . Zwykle w Angular możesz zmieniać dane
w dowolnym miejscu aplikacji przy użyciu dziedziczenia

obszary

działania i obserwacje. to
praktyczne, ale może również prowadzić do problemów, gdy nie jest jasne, które
część aplikacji odpowiada za modyfikację danych. Tutaj
dlaczego dyrektywy składników używają

odosobniony

zakres, więc cała klasa
manipulacja zakresem nie jest możliwa.

REF

:

NG-doc 1.5.6
Ale kiedy widzisz, że istnieje hak reklamy $ postLink (), możesz się zastanawiać, jaki jest tego powód?
Jeśli jednak przejrzysz opis tego haka, znajdziesz ...


Zapłacić

Zwróć uwagę, że elementy potomne zawierające


Dyrektywy templateUrl nie będą

skompilowane

i

połączony

ponieważ czekają na asynchroniczne załadowanie szablonu, a ich własna kompilacja i łączenie są wstrzymywane, dopóki to się nie stanie.

Proszę zapoznać się z odpowiedziami Stevena Lamberta poniżej ...
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Dokumentacja dla
$ postLink ()
jest poprawna. Jest wywoływana po połączeniu elementu kontrolera i jego elementów podrzędnych. Nie oznacza to, że od razu zobaczysz wynik dyrektywy. Może wywołuje
$ http
i wstawia wynik, gdy tylko się pojawi. Może to rejestracja obserwatora, który z kolei ustala wynik,

jak większość wbudowanych dyrektyw

Angular .
Głównym problemem w twoim przypadku jest to, że chcesz wykonać manipulacje DOM po

interpolacje zostały skompilowane

lub jeszcze lepiej, gdy zarejestrowany obserwator zdąży raz wystrzelić.
Niestety,

oficjalny sposób

zrób to nie. Istnieją jednak sposoby, aby to zrobić, ale nie znajdziesz ich w dokumentacji.
Dwa popularne sposoby

uruchomienie funkcji po kompilacji interpolacji

:
  • używając
    $ timeout
    bez opóźnienia (domyślnie 0):
    $ timeout (function () {/ * Twój kod jest tutaj */});
  • używając
    .ready ()
    , który jest dostępny Angular-mi jqLite-mi https://docs.angularjs.org/api ... ement

W twoim przypadku znacznie lepiej jest użyć obserwatora do uruchomienia funkcji, gdy tylko istnieje element o podanym identyfikatorze:
var deregistrationFn = $scope.$watch(() => {
return document.getElementById(this.gridId);
}, (newValue) => {
if (newValue !== null) {
deregistrationFn();// Your code goes here
}
});

Na koniec, moim zdaniem, uważam, że ilekroć trzeba czekać na kompilację interpolacji lub pewnych dyrektyw, aby wstawić ich wartość, nie stosuje się

Metoda budowania rzeczy

Kątowy. W twoim przypadku, dlaczego nie utworzyć nowego komponentu
myGridTable
, który wymaga
myGrid
jako jego elementu nadrzędnego i dodać tam odpowiednią logikę. W ten sposób obowiązki każdego komponentu są znacznie lepiej zdefiniowane i łatwiejsze do zweryfikowania.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się