14

O ile wiem, Angular kompiluje rzeczy na zasadzie "kto pierwszy, ten lepszy", co jest trudne. Zrobiłem dyrektywę, która otacza niektóre elementy i chcę mieć właściwość odsyłacza, która szuka rzeczy w treści.AngularJS - kolejność zmian, z której tworzone są dyrektywy

Na betonowym użytkowej przypadku: Robię dyrektywę Oznaczenie wejścia który wygląda wewnątrz zawartości dla pierwszego wejścia i dodaje losowo generowane id do input i atrybut do label

Tutaj for jest kod :

// Find the first element with the attribute ng-label-target or the first input and links a label to it 
app.directive('ngLabel', function() { 
    return { 
    restrict: 'E', 
    replace: true, 
    transclude: true, 
    scope: { 
     label: '@', 
    }, 
    template: '<span class="ng-label">' + 
       '<label class="ng-label-text">{{label}}</label>' + 
       '<span class="ng-label-content" ng-transclude></span>' + 
       '</span>', 
    link: function (scope, element, attrs) { 
     scope.id = scope.id || 'random-id-' + Math.floor(Math.random() * 90000000); 
     angular.element(element[0].querySelector('.ng-label-text')). 
     attr({for:scope.id}); 

     var target = angular.element(element[0].querySelector('[ng-label-target]')); 
     if (!target || target.length == 0) { 
     target = angular.element(element[0].querySelectorAll('input,select,textarea')[0]); 
     } 
     target.attr({id:scope.id}); 
    }, 
    }; 
}); 

Przykład Zastosowanie:

<ng-label label="Text:"> 
    <input type="text" ng-model="page.textColor" size="5" maxlength="7" placeholder="e.g. #000" required /> 
    <input ng-label-target type="color" ng-model="page.textColor" required /> 
</ng-label> 

To samo w sobie działa jak urok.

Jednak teraz chcę automatycznie wygenerować kilka wejść i mieć etykietę wskazującą na pierwszą. Problem polega na tym, że kiedy robię ng-repeat wewnątrz mojego ng-label, kod ng-repeat jest generowany po tym, jak moja dyrektywa została przetworzona, więc nic nie zostanie znalezione.

Dlatego moje pytanie brzmi: czy istnieje sposób, w jaki można określić kątowe, aby ocenić zagnieżdżone dyrektywy na lewą stronę zamiast odwrotnie?

Czy jest na to jakiś sposób, niż robię to obecnie?

Zrobiłem skrzypce, aby zilustrować kolejność oceniania rzeczy. Widać, że zewnętrzna Dyrektywa ma mniejszy lub równy wartości niż to zawartość (nie można zejść niżej niż mikrosekund, więc musiałem zrobić kilka powtórzeń):

http://jsfiddle.net/YLM9P/

+0

z pewnością wygląda o wiele bardziej skomplikowanie niż potrzeba ... dostarczona wersja demo ma zbyt dużą rekurencję, dostarcz wersję demonstracyjną za pomocą dyrektywy i znaczników. Możesz odkryć, że plunker jest łatwiejszy do tworzenia kanciastych wersji demo niż z skrzypcami. – charlietfl

+0

Dlaczego 'id' musi być losowy? Nie możesz po prostu użyć 'id =" name _ {{index}} "" i tego samego dla etykiety? –

+0

Nie chcę określać identyfikatora, ponieważ generalnie go nie potrzebuję, dlatego jest losowy, jeśli nie został określony. – Stefan

Odpowiedz

18

Od kątowych docs:

PRIORYTET Gdy istnieje wiele dyrektyw zdefiniowane na jednym elemencie DOM, czasami konieczne jest, aby określić kolejność, w jakiej są stosowane w dyrektywach. Priorytet służy do sortowania dyrektyw przed wywołaniem ich funkcji kompilacji. Priorytet jest zdefiniowany jako liczba. Dyrektywy o większym priorytecie numerycznym są kompilowane jako pierwsze. Funkcje pre-link są również uruchamiane w kolejności priorytetów, ale funkcje post-link są uruchamiane w odwrotnej kolejności. Kolejność dyrektyw o tym samym priorytecie jest niezdefiniowana. Domyślnym priorytetem jest 0.

TERMINAL Jeśli ma wartość true wtedy obecny priorytet będzie ostatni zestaw dyrektyw, które będzie wykonywał (wszelkie dyrektywy w obecnym priorytetem nadal będzie wykonywać jako zlecenie wykonania na samym priorytecie jest niezdefiniowany).

Dla Twojego problemu, wierzę, że ustawienie właściwości terminalu na wartość true rozwiąże problem.

app.directive('ngLabel', function() { 
    return { 
    restrict: 'E', 
    replace: true, 
    transclude: true, 
    .... 
    .... 
    terminal: true 
}); 
+1

Wygląda na to, że dyrektywy o niższym priorytecie są wykonywane jako pierwsze. – Ghigo

0

myślę, że można znacznie uprościć Twój kod i wyeliminuj zapytanie queryelectric (nie strasznie angularnie), dodając wyrażenie funkcji do elementu nadrzędnego (ewentualnie przekazując parametr), a następnie wywołując tę ​​funkcję z elementu (elementów) podrzędnego w ciągu powtórzenia ng. Funkcja po prostu ustawi wartość, którą będziesz wykorzystywał, a kiedy ją ustawisz, będziesz wiedział, że masz pierwszą, a resztę należy zignorować. Mogę być trochę bardziej konkretny, jeśli pokazałeś, jak powinien wyglądać końcowy HTML z nig-powtórzonymi polami wejściowymi.

0

Możesz spróbować zarejestrować MutationObserver, który nasłuchuje elementów dodanych do DOM. Ale to może być trochę głową do Twojego problemu - zdecydować;)

var observer = new MutationObserver(function(mutations) { 
    mutations.forEach(function(mutation) { 
    // you get notified about added DOM elements here 
    // check mutation.type if it was an insertion 
    // then you handle the first node specifically. 
    console.log(mutation.target.nodeName, mutation.type, mutation); 
    }); 
}); 

var config = {childList: true, attributes: false, characterData: false, subtree: false, attributeOldValue: false, characterDataOldValue: false}; 
observer.observe(element[0], config); 
 
Demo    http://plnkr.co/h6kTtq 
Documentation  https://developer.mozilla.org/en/docs/Web/API/MutationObserver 
Browser support http://caniuse.com/mutationobserver 
1

Problem ten, jak wiele innych w kątowe, można rozwiązać poprzez stworzenie dodatkowej dyrektywy:

app.directive('myLabelTarget', function() { 
return { 
    require: '^myLabel', 
    link: function(scope, element, attrs, myLabelCtrl) { 
    myLabelCtrl.doIfFirst(function(id) { 
     attrs.$set('id', id); 
    }); 
    } 
}; 
}); 

Za pomocą atrybutu require można uzyskać dostęp do kontrolera dyrektywy myLabel wyżej w DOM.

Zobacz przykład plnkr dla przykładu.

Powiązane problemy