Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
888 views
in Technique[技术] by (71.8m points)

angularjs - Injecting required dependencies with ng-controller

Using ui.router, we have a controller for a state:

controller('widget', function($repository, $stateParams){
    $scope.widget = $repository.get($stateParams.id);
})

registered with:

.state('widget',
       controller: 'widget',
       template: '/widgetTemplate.html'

We've come upon a case where we like to reuse this controller as part of a template:

<div ng-controller="widget" ng-include="/widgetTemplate.html"></div>

but there doesn't appear to be an easy way to inject a mocked $stateParams object with the proper ID. Something like:

<div ng-controller="widget" ng-inject="{$stateParams: {id: 1234}}" ng-include="/widgetTemplate.html"></div>

Outside of writing a custom directive that augments ng-controller or refactoring our code to make use of inherited scopes, are there any out-of-the-box ways to do this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I don't believe there is an out-of-the-box way. ng-controller just uses normal controller instantiation, and there is no opportunity to inject anything.

But this is an interesting "feature", which can be built, actually, relatively simply with a custom directive.

Here's an illustrative example (disclaimer: it is definitely not tested under obscure scenarios):

.directive("ngInject", function($parse, $interpolate, $controller, $compile) {
  return {
    terminal: true,
    transclude: true,
    priority: 510,
    link: function(scope, element, attrs, ctrls, transclude) {

      if (!attrs.ngController) {
        element.removeAttr("ng-inject");
        $compile(element)(scope);
        return;
      }

      var controllerName = attrs.ngController;

      var newScope = scope.$new(false);

      var locals = $parse(attrs.ngInject)(scope);
      locals.$scope = newScope;

      var controller = $controller(controllerName, locals);

      element.data("ngControllerController", controller);

      element.removeAttr("ng-inject").removeAttr("ng-controller");
      $compile(element)(newScope);
      transclude(newScope, function(clone){
        element.append(clone);
      });
      // restore to hide tracks
      element.attr("ng-controller", controllerName); 
    }
  };
});

The usage is as you described it:

<div ng-controller="MainCtrl">
  {{name}}
  <div ng-controller="SecondCtrl" ng-inject="{foo: name, bar: 'bar'}">
  </div>
</div>

And, of course, the controller can have these variables injected:

.controller("SecondCtrl", function($scope, foo, bar){
});

plunker


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...