范围与编译阶段

时间:2016-03-02 15:59:47

标签: angularjs angularjs-directive angularjs-scope

在下面的代码中,我试图在编译阶段添加一个按钮,并从范围分配ng-click到一个方法。 在链接阶段,通过调试我发现“compiledEle”包含按钮,然后ng-click也不会调用范围方法。

angular.module("app", [])
        .controller("ctrl1", function($scope){
            $scope.myModelObj = {
                name: 'Ratnesh',
                value: 100
            };
        })
        .directive("dirOne",function($compile){
            return {
                restrict: 'E',
                scope: {
                    myModel : "="
                },
                compile: function(ele){
                    ele.append("<button ng-click=\"showAlert()\">click ME</button>")
                    return {
                        post: function($scope, compiledEle){
                            $scope.showAlert = function(){
                                alert("The button is clicked");
                            };
                        }
                    };
                }

            };
        });

在编译阶段,范围方法没有绑定到按钮的原因可能是什么原因,但如果我在模板/ templateUrl中按下,则可以绑定相同的内容。如果在链接阶段我们包含一行:

,该方法也会被绑定
  

$编译(compiledEle.contents())($范围);)

如果不是在链接阶段添加“$ scope.showAlert”,它将被绑定到方法,我们已经在控制器中有了方法!!!

    .controller("ctrl1", function($scope){
                $scope.myModelObj = {
                    name: 'Ratnesh',
                    value: 100
                };
                $scope.showAlert = function(){
                    alert("The button is clicked");
                };
            })

编译方法是做DOM操作,链接阶段是将编译好的html链接到范围。所以我们可以在编译期间向DOM添加新元素,在链接阶段添加新范围方法,那么我的期望在哪里出错?

1 个答案:

答案 0 :(得分:3)

问题是你的编译函数在编译时还无法访问元素实例的范围。

您希望app.directive("fromCompile", function($compile) { return { restrict: 'E', scope: {}, compile: function(tElement) { // When AngularJS compiles the template element, it does not have // access yet to the scope of the iElement, because the iElement does // not exist yet. // You want ng-click to execute a method of the iElement scope // which does not exist here yet because you are modifying the // template element, not the instance element. // This will not give you the effect you are looking for because it // will execute the function in a scope higher up the scope hierarchy. tElement.append('<button ng-click=\"showAlert()\">Using compile: click me (this will not work correctly)</button>'); return { post: function(scope, iElem, iAttrs) { scope.showAlert = function() { alert("This button was added using compile"); }; } }; } }; }); 执行实例范围的方法,该方法在编译模板时尚不可用。

我在代码中添加了注释来说明会发生什么:

app.directive("fromTemplate", function($compile) {
  return {
    restrict: 'E',
    scope: {},
    template: "<button ng-click=\"showAlert()\">Using template: click me (this will work)</button>",
    link: function(scope, iElem, iAttrs) {
      scope.showAlert = function() {
        alert("This button was added using template");
      };
    }
  };
});

要解决此问题,您可以使用模板让AngularJS自动为您编译模板:

app.directive("fromLink", function($compile) {
  return {
    restrict: 'E',
    scope: {},
    link: function(scope, iElem, iAttrs) {
      var linkFn = $compile("<button ng-click=\"showAlert()\">Using link: click me (this will work)</button>");
      var button = linkFn(scope);
      iElem.append(button);
      scope.showAlert = function() {
        alert("The button was added using $compile in link function");
      };
    }
  };
});

或者在元素实例的链接函数中自己手动编译模板(因为你可以在那里访问正确的范围):

{{1}}

我创建了一个包含所有代码和工作版本right here的Plunk。

希望有所帮助!