2015-01-08 4 views
2

На какой стадии процесса компиляции/связи есть переменные из изолированной области действия директивы, связанной с областью родительского (контроллера)? У меня есть приложение, в котором я хочу автоматически вызвать директиву api, как только будет загружено представление.Когда изолированная область привязана к родительской области в AngularJs?

Я понял, что привязка к сфере видимости happens in the directive linking phase, так что при связывании ссылок переменные, открытые в изолированной области видимости, должны быть доступны в родительской области.

Однако я считаю, что это не так, как показано в приведенном ниже коде (plunker here).

//plunker code 
var app = angular.module('plunker', []); 

app.controller('MainCtrl', function($scope) { 
    $scope.name = 'World'; 

    $scope.buttonClick = function() { 
    console.log("In buttonClick function, call is: " + this.call); 
    this.call(); 
    } 

    $scope.$on("LinkComplete", function(event) { 
    console.log("In LinkComplete, call is: " + event.currentScope.call); 
    //event.currentScope.call(); 
    }); 

    console.log("In Constructor, call is: " + this.call); 
}) 
.directive('myDirective', function(){ 
    return { 
    scope: { 
     myMethod: '=' 
    }, 
    controller: function ($scope) { 
     $scope.myMethod = function() { 
     alert("method called"); 
     }; 
    }, 
    link: function postLink(scope) 
    { 
     scope.$emit("LinkComplete"); 
    } 
    }; 
}); 

<body ng-controller="MainCtrl"> 
    <p>Hello {{name}}!</p> 
    <div my-directive my-method="call"></div> 
    <button ng-click="buttonClick()">Call</button> 
</body> 

Обратите внимание, что код пытается получить доступ к связанную переменную (которая указывает на способ на контроллере директивы) дважды во время просмотра инициализации, и в обоих случаях, переменная не определена. Я бы не ожидал, что переменная будет доступна во время конструктора основного контроллера, но я ожидаю, что она будет доступна во время обработчика события post-link. После загрузки представления доступны связанные переменные (нажмите кнопку «Вызов» для просмотра).

Как я могу получить доступ к связанным переменным с контроллера, не требуя от пользователя щелчка по кнопке или тому подобному?

+0

Хорошо, я мог бы сказал, что более четко (отредактирован для этого эффекта). Я имел в виду, когда переменные из изолированной области привязаны к родительской области. –

+1

@pixelbits почему бы и нет? O thout это двухсторонняя привязка. Если вы измените его в изолированной области видимости, он изменит его в родительской области, не так ли? –

+0

@pixelbits Если вы запустите код и нажмите кнопку «Вызов», вы увидите, что контроллер имеет доступ к функции myMethod() на контроллере директивы с помощью переменной области, называемой вызовом. Это доказывает правильность настройки двусторонней привязки, которую я хочу настроить. Мой вопрос: * когда * в процессе компиляции доступно привязку? –

ответ

2

Это хороший вопрос, когда вы видите несколько слов типа «x is y in z stage», вам нужно быть осторожным с точностью, всегда копайте исходный код, чтобы доказать это.

Ваш plunker использует v1.2.27, проверка этой линии: https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1492

isolateScope.$watch(function parentValueWatch() { 
    var parentValue = parentGet(scope); 
    if (!compare(parentValue, isolateScope[scopeName])) { 
    // we are out of sync and need to copy 
    if (!compare(parentValue, lastValue)) { 
     // parent changed and it has precedence 
     isolateScope[scopeName] = parentValue; 
    } else { 
     // if the parent can be assigned then do so 
     parentSet(scope, parentValue = isolateScope[scopeName]); 
    } 
    } 
    return lastValue = parentValue; 
}, null, parentGet.literal); 

Это будет оцениваться в следующем $ переваривать цикл и затем parentScope.call будет назначен. В то же время, функция postLink выполняется синхронно прямо под ним: https://github.com/angular/angular.js/blob/v1.2.27/src/ng/compile.js#L1575

// POSTLINKING 
for (i = postLinkFns.length - 1; i >= 0; i--) { 
    try { 
    linkFn = postLinkFns[i]; 
    linkFn(linkFn.isolateScope ? isolateScope : scope, $element, attrs, 
     linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers), transcludeFn); 
    } catch (e) { 
    $exceptionHandler(e, startingTag($element)); 
    } 
} 

После postLink был выполнен, контроллер получил событие, но parentScope.call еще не инициализируется с помощью $ дайджеста.

Так что, если вы добавите SetTimeout, чтобы проверить, это выглядит как то, что вы хотите:

$scope.$on("LinkComplete", function(event) { 
    setTimeout(function() { 
     console.log("In LinkComplete, call is: " + event.currentScope.call); 
     //event.currentScope.call(); 
    }); 
}); 
+0

Отлично, спасибо, что работает! Я не знал, что функция $ timeout/setTimeout (callback) ждет, пока текущий цикл дайджеста не завершится до выполнения обратного вызова.И это не в документах, но, похоже, это работает именно так. –

Смежные вопросы