如何在角度js中管理来自控制器的指令

时间:2015-06-19 11:03:20

标签: angularjs design-patterns

我正在寻找一种角度模式来实现离子库对其委托模式的作用。

slide box component,例如:

在视图中使用其指令(<ion-slide-box>)时,您可以自动在控制器中注入与指令对象关联的某种服务($ionicSlideBoxDelegate),您可以使用它来控制它方法如:

$ionicSlideBoxDelegate.start()    // Start sliding again if the slideBox was stopped
$ionicSlideBoxDelegate.stop()     // Stop sliding
$ionicSlideBoxDelegate.next()     // Go to the next slide.
$ionicSlideBoxDelegate.previous() // Go to the previous slide
//...

我最好的尝试:

  1. 创建一个带有隔离范围的指令,该范围只接收一个参数(委托服务对象)
  2. 控制器中的
  3. 实例化此Delegate服务的新实例并将其附加到$scope
  4. 视图中的
  5. 将实例传递给指令
  6. 的Delegate服务

    以下是一些代码来说明我的解决方案。在这个例子中,我试图创建一个伪进度条指令,它将像普通进度条一样运行,但它会自动前进,除非我们将它告诉stop。除非通过致电complete告知,否则它永远不会达到100%。

    该指令及其附加的Handler(或委托):

    angular.module("fakeProgressbar", [])
    .directive 'fakeProgressbar', ->
      scope:
        handler: '='
      restrict: 'E'
      replace: false
      template: '
          <progressbar class="progress-striped active" max="handler.config.max" type="{{handler.config.type}}" value="handler.config.value">
            {{ handler.config.value }} %
          </progressbar>
          '
    .factory 'FakeProgressbarHandler', ($interval, $timeout, $q) ->
      class FakeProgressbar
        start: -> # ...
        success: -> # ...
        complete: -> # ...
        stop: -> # ...
    

    在您的控制器中:

    angular.module("app", ["ui.bootstrap", "fakeProgressbar"])
    .controller "fakeProgressbarExampleController", ($scope, FakeProgressbarHandler) ->
      $scope.fakeProgressbarHandler = new FakeProgressbarHandler()
      $scope.fakeProgressbarHandler.start() # start animation inmediately
    
      # now you can do `$scope.fakeProgressbarHandler.stop()` or `$scope.fakeProgressbarHandler.complete()` 
    

    在您的观点中:

    <fake-progressbar handler="fakeProgressbarHandler"></fake-progressbar>
    

    此工作代码的完整示例可在此处找到:http://plnkr.co/edit/Ehsuu1nKxeu2W7ktTVFC?p=preview

    问题:

    当然,问题是如何摆脱必须将fakeProgressbarHandler附加到范围以便稍后将其传递回指令。

    离子委托模式似乎是自动实现的。

1 个答案:

答案 0 :(得分:1)

离子代表没有太多魔力。无论何时使用该指令,控制器都会使用delegateService注册实例。例如在slideBox中:

https://github.com/driftyco/ionic/blob/master/js/angular/directive/slideBox.js#L127

var deregisterInstance = $ionicSlideBoxDelegate._registerInstance(
  slider, $attrs.delegateHandle, function() {
    return $ionicHistory.isActiveScope($scope);
  }
);

委托代码主要在这里找到:

https://github.com/driftyco/ionic/blob/master/js/utils/delegateService.js

  DelegateService.prototype._registerInstance = function(instance, handle, filterFn) {
    var instances = this._instances;
    instance.$$delegateHandle = handle;
    instance.$$filterFn = filterFn || trueFn;
    instances.push(instance);

    return function deregister() {
      var index = instances.indexOf(instance);
      if (index !== -1) {
        instances.splice(index, 1);
      }
    };
  };

以下是注册(未经测试)的简化示例:

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

app.controller('firstController', function($scope, DelegateService) {
  $scope.start = function(handle) {
    DelegateService.getInstance(handle).start();
  };
  $scope.stop = function(handle) {
    DelegateService.getInstance(handle).stop();
  };
});

app.controller('secondController', function($scope, DelegateService) {
  $scope.startAll = function() {
    Object.keys(DelegateService._instances).forEach(function(handle) {
      DelegateService._instances[handle].start();
    });
  };
  $scope.stopAll = function(handle) {
    Object.keys(DelegateService._instances).forEach(function(handle) {
      DelegateService._instances[handle].stop();
    });
  };
});

app.directive('someDirective', function(SomeDirectiveDelegate, DelegateService) {
  return {
    scope: {},
    controller: function($scope, $element, $attrs) {
      $scope.progress = {
        amount: 0
      };
      var delegate = new SomeDirectiveDelegate($scope.progress);
      DelegateService._registerInstance(delegate, $attrs.handle);
    },
    template: '<div>{{ progress.amount }}</div>'
  };
});

app.factory('SomeDirectiveDelegate', function($interval) {
  function SomeDirectiveDelegate(progress) {
    var interv;

    function stop() {
      if (interv) {
        $interval.cancel(interv);
        interv = null;
      }
    }

    function start() {
      stop();
      interv = $interval(function() {
        progress.amount += 1;
      }, 100);
    }

    return {
      start: start,
      stop: stop,
    };
  }
  return SomeDirectiveDelegate;
});

app.service('DelegateService', function() {
  this._instances = {};
  this._registerInstance = function(instance, handle) {
    this._instances[handle] = instance;
  };
  this.getInstance = function(handle) {
    return this._instances[handle];
  };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app'>
  <div ng-controller='firstController'>
    <some-directive handle="1"></some-directive>
    <button ng-click="start(1)">start1</button>
    <button ng-click="stop(1)">stop1</button>
    <some-directive handle="2"></some-directive>
    <button ng-click="start(2)">start2</button>
    <button ng-click="stop(2)">stop2</button>
  </div>
  <hr>
  <div ng-controller='secondController'>
    <button ng-click="startAll()">start all</button>
    <button ng-click="stopAll()">stop all</button>
  </div>
</div>