2

While developing my first Angular.js project I ran into troble. After a day-long research I have no idea how to override a plugin controller method.

I am using a pretty nice https://github.com/ManifestWebDesign/angular-gridster plugin, but some of controller functions (for example GridsterCtrl.updateHeight) does not suit my tasks well.

Keeping in mind that editing plugin code is a bad idea (because I want to keep Gridster up to date using http://bower.io/), I understand that Gridster controller functions need to be overridden elsewhere.

It seems directives are not helping in this case, so how should the override be done -- or am I facing completely wrong direction here?

Thank you for your time.

Ruskin
  • 5,721
  • 4
  • 45
  • 62
gloomy
  • 83
  • 2
  • 5

1 Answers1

3

It is not a bad thing at all what you are wanting to do, but i would suggest inheriting from the controller and overriding what you need. I like the two different methods explained in this blog

For the longevity of this answer, I am copying some excerpts.

In AngularJS it is trivial to request any defined dependency at any point via the $injector service. This is easy to abuse in ways that will make your life difficult later, but it also has its uses. Here is how we can use it to arrange controllers into an inheritance hierarchy, starting with the definition of a generic parent controller:

function ParentController($scope, myService) {
  // In this form of inheritance, properties are set in reverse order: child sets 
  // first, then parent. So a property that is intended to be overridden has to
  // check for its own existence.
  //
  // e.g. Only create this function if it hasn't already been set by the child.
  this.decorateScope = this.decorateScope || function () {
    $scope.decorator = myService.getDecorator() + 2;
  }

  // Setting up an initialize function is another necessary part of enabling child
  // controllers to override features of the parent. All setup is delayed to the
  // end of instantiation, allowing individual functions and properties to be 
  // overridden first.
  this.initialize = this.initialize || function () {
    this.decorateScope();
  }

  // This will be invoked last of all when a child controller is instantiated.
  initialize();
}

Next we define a child controller that inherits from the parent above:

function ChildController($injector, $scope, myService) {
  // Override the parent function while still allowing further children to override
  // it.
  this.decorateScope = this.decorateScope || function () {
    $scope.decorator = 44;
  }

  // This is the magic by which this controller inherits from the ParentController.
  // Essentially the ParentController function is invoked on "this" and is passed
  // dependencies directly.
  // 
  // Note that this means a child controller must have all of the dependencies
  // required by the parent.
  $injector.invoke(ParentController, this, {
    $scope: $scope,
    myService: myService
  });
}

It is actually possible to skip passing any dependencies other than $scope from the child to the parent controller. Everything will work until you start to write test code in which you are injecting mock dependencies. Any dependency that is not explicitly passed into $injector.invoke() will be instantiated as the real thing, not the mock specified in the test case. This is obviously very inconvenient and will completely sabotage your tests - so always pass in all of the dependencies explicitly.

This method of inheritance supports convenient mixins, as a mixin works in exactly the same way as inheritance:

function ChildController($injector, $scope, myService, otherService) {
  // Any number of controllers can be invoked in this way. They will apply
  // their properties and overrides in the order they are invoked. So if you
  // want a mixin to override the parent, it has to come first.
  $injector.invoke(MixinController, this, {
    $scope: $scope,
    otherService: otherService
  });
  $injector.invoke(ParentController, this, {
    $scope: $scope,
    myService: myService
  });
}
Joel Jeske
  • 1,618
  • 14
  • 17
  • Thank you for response, i actually saw this article, but could not figure out how to use inheriting controller in my case. The reality is in Gridster i was dealing with directives controller (yeah, found out after asking) so for me the solution is to use "requere" in my own directive like explained [here](https://docs.angularjs.org/guide/directive#creating-directives-that-communicate) and its seems to me like its all good now. Nevertheless, you gave a proper answer for my initial question – gloomy May 22 '14 at 09:46