ред за изпълнение на функцията на директивната връзка

Аз съм нов в цялата тази ъглова...

Имам персонализирана директива, нека я наречем myDar. Вътре в тази директива дефинирам функция за връзка. В моя html искам да използвам множество вложени тагове на тази директива, както следва:

<myDar id="outer"><myDar id="inner"></myDar></myDar>

Искам първо да се изпълни функцията за връзка на "outer". Как да направя това?

Това е общият въпрос. Ако това помага, тогава това, което наистина се опитвам да направя, е да създам директиви, които обгръщат оформлението на jquery ui (връзка към уебсайта) . Така че имам директива за "ui-layout" и директиви за "center", "west" и т.н. В директивата "ui-layout" се обаждам на $(tElm).layout(options). Имам проблем при създаването на вложено оформление:

<ui-layout class="layout-container">
    <ui-layout-center>
        <ui-layout>
            <ui-layout-center>inner center</ui-layout-center>
            <ui-layout-west>inner west</ui-layout-west>
        </ui-layout>        
    </ui-layout-center>
    <ui-layout-west>west</ui-layout-west>
</ui-layout>

Angular изпълнява първо функцията за връзка на вътрешната директива "ui-layout", но за да работи плъгинът за оформление на jquery ui, той изисква първо да извика $(tElm).layout(options) на външния, в противен случай оформлението не се изобразява правилно.


person julius_am    schedule 15.01.2014    source източник
comment
Можете ли да обясните подробно какво трябва да стартирате в коя функция за свързване?   -  person Ilan Frumer    schedule 15.01.2014
comment
Между другото angular.module('app').directive('myDar' ... ще регистрира myDar като snake-case в html <my-dar>...</my-dar>   -  person Nate-Wilkins    schedule 27.02.2014


Отговори (2)


За това ще се възползвате от контролера на директивата. Това ще бъде клас, дефиниращ метод за регистриране на вложени контролери и друг за изпълнение на желаната команда (тук $(...).layout(...)) на този елемент и след това на всичките му деца. Това означава, че външната директива е отговорна за координирането на създаването на оформленията.

Пълният примерен код е:

app.directive("y", function() {
    function Controller($element) {
        this.$element = $element;
        this.children = [];
    }

    Controller.prototype.register = function(child) {
        this.children.push(child);
    };

    Controller.prototype.execute = function() {
        console.log("PAYLOAD: " + this.$element.attr("id"));
        for( var i=0; i < this.children.length; i++ ) {
            this.children[i].execute();
        }
    };

    return {
        require: "y",
        controller: ["$element", Controller],
        link: function(scope, element, attrs, ctrl) {
            var e = element.parent(), nested = false;
            while( e != null ) {
                if( e.controller("y") != null ) {
                    e.controller("y").register(ctrl);
                    nested = true;
                    break;
                }
                e = e.parent();
                if( typeof(e.tagName) === "undefined" ) break; //XXX Needed, at least for fiddle
            }
            if( !nested ) ctrl.execute();
        }
    };
});

Заменете реда console.log("PAYLOAD: " + this.$element.attr("id")); с действителния код за изпълнение. Вижте съответната цигулка: http://jsfiddle.net/8xSjZ/

Ако външната директива беше различна от текущата, получаването на родителския контролер би било толкова лесно, колкото изискването "?^y". В този случай ни дава текущия контролер, следователно трябва сами да зациклим (e.parent()).

person Nikos Paraskevopoulos    schedule 15.01.2014
comment
Страхотен отговор. Един въпрос: как работи e.controller(y)? Това извиква ли директно конструктора на класа Controller? - person Faredoon; 25.08.2014
comment
Здравей, благодаря. Всъщност e.controller() е Angular разширение на jqLite (или jQuery). Документирано е тук - потърсете jQuery/jqLite Extras. Това, което прави накратко, е, че намира съществуващ контролер с даденото име, прикачен към елемента. Така че не извиква конструктора, той очаква контролерът вече да е конструиран и прикачен към елемента. - person Nikos Paraskevopoulos; 26.08.2014
comment
Благодаря ти. Оценявам го. - person Faredoon; 26.08.2014
comment
Още един въпрос: Помислете, че нямам вложена директива, така че имам нещо като ‹div level=1 id=a y=›, последвано от друго ‹div id=other level=2 y=›. Докато обработвам първия div във функцията за връзка, бих искал да получа достъп до втория div с помощта на angular.element(div[level='2']) и впоследствие контролера с помощта на .controller(y). Вижте този plunkr: plnkr.co/edit/oIpvQP. Получавам JQLite изключение. Търсенето на елементи чрез селектори не се поддържа от jqLite! Вижте: docs.angularjs.org/api/angular.element - person Faredoon; 27.08.2014
comment
Ще трябва да включите jQuery за това, така че Angular да използва jQuery вместо jQlite. jQlite е реализация на съкратена версия на jQuery API. Той не поддържа този вид селектор (т.е. "div[level='2']"). Предполагам, че трябва да има някакъв друг начин да направите това чрез реорганизиране на вашата логика. - person Nikos Paraskevopoulos; 27.08.2014

В зависимост от точния случай на употреба функция compile може да е подходяща. compile функции се изпълняват преди link функции и - което е по-важно - в обратен ред. Това означава първо родител.

app.directive("ui-layout", function() {
  return {
    restrict: 'E',
    compile: function(element, attrs) {
               //do layout stuff here
               //return a link function or nothing

Друго решение може да бъде да изпълните съответния код на дъщерните си директиви с помощта на $timeout.

app.directive("ui-layout-center", function($timeout) {
  return {
    restrict: 'E',
    link: function(scope, element, attrs) {
            $timeout(function() {
              //do layout stuff later
             }, 0);  
person a better oliver    schedule 15.01.2014
comment
$timeout без секунда свърши работа за мен, тъй като отлага до следващия цикъл на дайджест. - person Soviut; 19.03.2014