AngularJS - 在指令之间传递范围

时间:2015-08-13 03:34:09

标签: angularjs angularjs-directive angularjs-scope

为了抽象,我试图在指令之间传递范围但收效甚微......基本上,这是一种模态类型的场景:

指令A - 处理屏幕元素的点击功能:

.directive('myElement', ['pane', function(pane){
return {
    restrict: 'A',
    scope: {},
    link: function(scope,elem,attrs){

        //im going to try and call the form.cancel function from a template compiled in another directive

        scope.form = {
            cancel: function(){
                pane.close();
            }
        };

        scope.$watch(function(){
            var w = elem.parent()[0].clientWidth;
            elem.css('height',(w*5)/4+'px');
        });
        elem.on('click', function(){

            //this calls my service which communicates with my other directive to 1) display the pane, and 2) pass a template compiled with this directive's scope

            pane.open({
                templateUrl: 'views/forms/edit.html',
                scope: scope //I pass the scope to the service API here
            });
        });
    }
}
}])

我有一个名为'Pane'的服务来处理API:

.service('pane',['$rootScope', function($rootScope){
    var open = function(data){
        $rootScope.$broadcast('openPane',data); //this broadcasts my call to open the pane with the template url and the scope object
    };
    var close = function(){
        $rootScope.$broadcast('closePane');
    };
return {
    open: open,
    close: close
}
}]);

最后,指令B正在等待'openPane'广播,其中包括模板网址和范围:

.directive('pane',['$compile','$templateRequest','$rootScope', function($compile,$templateRequest,$rootScope){
return {
    restrict: 'A',
    link: function(scope,elem,attrs){
        var t;
        scope.$on('openPane', function(e,data){ //broadcast is received and pane is displayed with template that gets retrieved
            if(data.templateUrl){
                $templateRequest(data.templateUrl).then(function(template){

                    //this is where the problem seems to be. it works just fine, and the data.scope object does include my form object, but calling it from the template that opens does nothing
                    t = $compile(template)(data.scope); 

                    elem.addClass('open');
                    elem.append(t);
                }, function(err){
                    console.log(JSON.stringify(err));
                });
            }
            else if(data.template){
                t = $compile(angular.element(data.template))(data.scope);
                elem.addClass('open');
                elem.append(t);
            }
            else console.log("Can't open pane. No templateUrl or template was specified.")
        });
        scope.$on('closePane', function(e,data){
            elem.removeClass('open');
            t.remove();
        });
    }
}
}])

问题是,当最后一个指令'pane'接收到'openPane'广播时,它会打开并附加模板就好了,但当我调用我的原始指令中定义的函数'form.cancel()'时像这样:

<button type="button" ng-click="form.cancel()">Cancel</button>

......没有任何反应。事实是,我不确定我所做的事情是否合法,但我想明白为什么它不起作用。这里的最终目标是能够将一个指令的范围与表单模板一起传递给Pane指令,因此我的所有表单(由它们自己的指令控制)都可以“注入”窗格。 / p>

1 个答案:

答案 0 :(得分:0)

如果没有正在运行的示例,我会怀疑在传递到您的窗格模板时可能的原因是作用域的范围。在编译窗格模板时,作用域本身会被传递和使用,但是它的闭包在此过程中会丢失,因此您可能无法看到pane服务,它是指令工厂闭包的一部分而{{{} 1}}使用。

我写了一个简单的例子,它确实有效,并且不依赖于闭包而非局部变量。如果您在form.cancel函数上调用.bind(pane)并在scope.form.cancel替换pane内,则可以完成类似的操作。

所以这里是working example,这是它的代码:

this

页面模板非常简单:

/* ************ */
/* Pane service */

class PaneService {

  constructor($rootScope) {
    console.log('pane service instantiated.', this);
    this.$rootScope = $rootScope;
  }

  open(template, scope) {
    this.$rootScope.$emit('OpenPane', template, scope);
  }

  close(message) {
    this.$rootScope.$emit('ClosePane', message);
  }
}
PaneService.$inject = ['$rootScope'];

/* ************************* */
/* Pane directive controller */

class PaneController {
  constructor($rootScope, $compile, $element) {
    console.log('pane directive instantiated.', this);
    this.$compile = $compile;
    this.$element = $element;
    $rootScope.$on('OpenPane', this.open.bind(this));
    $rootScope.$on('ClosePane', this.close.bind(this));
  }

  open(event, template, scope) {
    console.log('pane directive opening', template, scope);
    var t = this.$compile(template)(scope);
    this.$element.empty().append(t);
  }

  close(evet, message) {
    console.log('pane directive closing', message);
    this.$element.empty().append('<strong>' + message + '</strong>');
  }
}
PaneController.$inject = ['$rootScope', '$compile', '$element'];

var PaneDirective = {
  restrict: 'A',
  controller: PaneController,
  controllerAs: 'pane',
  bindToController: true
}

/* *************** */
/* Page controller */

class PageController {
  constructor(paneService, $scope) {
    console.log('page controller instantiated.', this);
    this.paneService = paneService;
    this.$scope = $scope;
  }

  open() {
    console.log('page controller open', this);
    this.paneService.open('<button ng-click="page.close(\'Closed from pane\')">Close from pane</button>', this.$scope);
  }

  close(message) {
    console.log('page controller close');
    this.paneService.close(message);
  }
}
PageController.$inject = ['paneService', '$scope'];

angular
  .module('App', [])
  .service('paneService', PaneService)
  .directive('pane', () => PaneDirective)
  .controller('PageController', PageController);