【问题标题】:Get AngularJS to compile directive and link function before executing the controller在执行控制器之前获取AngularJS编译指令和链接函数
【发布时间】:2014-01-04 13:37:18
【问题描述】:

由于我的程序的性质,我需要将函数放在作用域上并在指令的链接函数和控制器之间共享,就像这样..

.controller("controller", function($scope, $location, $timeout, model) {

    //irrelevant code

    $scope.addObject(draggables[i]);

};


.directive("designCanvas", function($timeout) {
    return {
        restrict: "A",
        link: function($scope, element) {

            $scope.addObject = function(draggable) {

                // irrelevant code
            }
        }
    }
}

当我调用这个函数时,我得到'$scope.addObject 不是一个函数'。

我的问题是控制器在 angularJS 评估链接函数之前执行,因为当我使用 $timeout 将其延迟几秒钟时,函数调用工作正常

所以我的问题是,我怎样才能让链接函数的内容先编译?

【问题讨论】:

  • 编译依赖于 HTML 图 (DOM)。如果控制器是在指令的父级上定义的,它将在链接发生之​​前被实例化。为什么不能将 addObject 添加到控制器。或查看if($scope.addObject) $scope.addObject(draggables[i]);
  • 感谢您的宝贵时间 :) 我在指令中使用 easelJS 来操作画布,它的变量是链接函数的本地变量,因此我无法在控制器中进行修改。我也在尝试创建一些分离并具有更结构化的 MVC 格式.. if($scope.addObject) 可以工作,但不太符合我的目的,因为无论如何我都需要执行该函数

标签: angularjs hyperlink angularjs-directive angularjs-scope


【解决方案1】:

我建议将此函数编写为服务并将服务注入指令和控制器。 共享功能应作为服务实现。

.factory("objectService",function(){
    return {
       addObject : function (draggable){
          //your code of this function
       }
    };
});

.controller("controller", function($scope, $location, $timeout, model,objectService) {

    //irrelevant code

    $scope.addObject = function (draggable){
        objectService.addObject(draggable); //reuse this function
       //objectService.addObject.call($scope,draggable) if you want to call this function with $scope as the context.
    };
};

.directive("designCanvas", function($timeout,objectService) {
    return {
        restrict: "A",
        link: function($scope, element) {
            $scope.addObject = function(draggable) {
                objectService.addObject(draggable); //reuse this function.
                //objectService.addObject.call($scope,draggable) if you want to call this function with $scope as the context.

                //write more logic specific to this function, like modifying link's local data.
            }
        }
    }
}

【讨论】:

  • 谢谢 :) 如果我需要 addObject 函数来修改链接函数中保存的变量,这将如何工作?
  • @Tom Hadkiss:如果该逻辑仅特定于链接功能(控制器没有此逻辑)=>此逻辑不共享。你可以写在objectService.addObject(draggable);下面
  • @Tom Hadkiss:如果控制器和指令都具有相同的逻辑 => 此逻辑是共享的,您可以将更多参数传递给 objectService.addObject 并将您的逻辑写入其中。
  • 该方法只会修改链接函数的本地变量,因此不会共享。我很困惑你把它写在下面是什么意思?具体写什么?再次感谢
  • @Tom Hadkiss:在链接功能中查看我的更新。希望现在更清楚了
【解决方案2】:

我会在控制器中创建$watch,以监听指令中的某些标志。

类似:

.controller("controller", function($scope, $location, $timeout, model) {

    //irrelevant code
    $scope.flag = false; 

     $scope.$watch(function () {
        return $scope.flag;
    },
    function (newValue, oldValue) {
        if(newValue == true){
            $scope.addObject(draggables[i]);
         }
    }, true);


};


.directive("designCanvas", function($timeout) {
    return {
        restrict: "A",
        link: function($scope, element) {
            $scope.flag = true;
            $scope.addObject = function(draggable) {

                // irrelevant code
            }
        }
    }
}

有点乱,但我认为这是一个方向。取而代之的是$scope.flag,您可以尝试使用如下回调:

 .controller("controller", function($scope, $location, $timeout, model) {

     $scope.callback= function() {
       $scope.addObject(draggables[i]);
     }
    };

.directive("designCanvas", function($timeout) {
        return {
            restrict: "A",
            link: function($scope, element) {

                $scope.addObject = function(draggable) {

                  // ....

                  $scope.callback();
                }
            }
        }
    }

希望对你有帮助,

【讨论】:

    【解决方案3】:

    我会创建另一个指令并使其依赖于designCanvas

    .directive("designCanvas", function() {
        return {
            controller: function() {
                this.addObject = function(draggable) {
                    alert(draggable.name);
                }
            }
        }
    })
    
    .directive("draggable", function() {
        return {
            require: '^designCanvas',
            link: function(scope, element, attrs, designCanvasController) {
                designCanvasController.addObject(scope.item);
            }
        }
    });
    

    这样使用:

    <div design-canvas>
        <div ng-repeat="item in draggables" draggable>{{item.name}}</div>     
    </div>
    

    演示plunker.

    我认为,将指令绑定到控制器并不是最好的主意。您应该选择服务或另外一个指令。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-14
      • 1970-01-01
      • 1970-01-01
      • 2015-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多