$onInit and new require Object syntax in Angular components blog post

$onInit and new require Object syntax in Angular components

Todd Motto

Todd Motto

11 Feb, 2016

4 minutes read

The component() helper method shipped with so many great features to take us even closer towards Angular (v2+) syntax and integration. Let’s explore the $onInit method and the new require property’s syntax that makes the component() method much more powerful. If you’ve not checked out the component() method just yet, check my write-up on it here.

$onInit

Finally, the much needed callback when a component is mounted and ready – $onInit! It’s easy to use and is part of the component’s controller. See this example for usage:

angular
  .module('app', [])
  .component('parentComponent', {
    transclude: true,
    template: `
      <div ng-transclude></div>
    `,
  })
  .component('childComponent', {
    bindings: {
      count: '='
    },
    controller: function () {
      this.state = 'Not loaded';
      this.$onInit = function() {
        this.state = 'Loaded!';
      };
    },
    template: `
      <div>
        Component: {{ $ctrl.state }}
      </div>
    `
  });

And a live example:

Angular has the ngOnInit method, a great lifecycle callback that will help us transition from AngularJS 1.x. ngOnInit is called right after the directive’s data-bound properties have been checked for the first time, and before any of its children have been checked. It is invoked only once when the directive is instantiated – much like in this AngularJS 1.x implementation.

Using “require” as an Object

Previously with Directives we used “require” to inherit methods from another Directive. This syntax was a simple String or Array, for example:

angular
  .module('app', [])
  .directive('parentComponent', function () {
    scope: {},
    require: ['^parentDirective', 'ngModel'],
    controller: function () {
      // controller logic
    }
    link: function ($scope, $element, $attrs, $ctrl) {
      // $ctrl[0] === ^parentDirective
      // $ctrl[1] === ^ngModel
    },
    template: `
      <div>
        Component: {{ $ctrl.state }}
      </div>
    `
  });

Note how in the above example the require property is an Array, which is horribly passed to the link function as $ctrl, where we can access the Array index such as $ctrl[0] to get specific Controllers that we need.

Thankfully, this is much nicer inside the component() method.

First, let’s add a method to the parentComponent Controller and a simple ng-transclude to pass a child Component into:

angular
  .module('app', [])
  .component('parentComponent', {
    transclude: true,
    template: `
      <div ng-transclude></div>
    `,
    controller: function () {
      this.foo = function () {
        return 'Foo from parent!';
      };
    }
  });

Then, we add the childComponent and declare require as an empty Object, empty Controller and placeholder {{ $ctrl.state }} inside the template:

angular
  .module('app', [])
  .component('parentComponent', {
    transclude: true,
    template: `
      <div ng-transclude></div>
    `,
    controller: function () {
      this.foo = function () {
        return 'Foo from parent!';
      };
    }
  })
  .component('childComponent', {
    require: {},
    controller: function () {

    },
    template: `
      <div>
        Component! {{ $ctrl.state }}
      </div>
    `
  });

Next up, a nice syntax change, the require property is an Object, not a String|Array as we saw in Directives!

angular
  .module('app', [])
  ...
  .component('childComponent', {
    require: {
      parent: '^parentComponent'
    },
    ...
  });

This allows us to now use this.parent as an inherited reference inside the childComponent‘s Controller:

angular
  .module('app', [])
  ...
  .component('childComponent', {
    require: {
      parent: '^parentComponent'
    },
    controller: function () {
      this.parent.foo();
    },
    ...
  });

But wait, this will throw an Error – it’s trying to call this.parent.foo(); before the Component is even ready. So let’s use the $onInit method that we just learned to be able to call it when it’s mounted:

angular
  .module('app', [])
  ...
  .component('childComponent', {
    require: {
      parent: '^parentComponent'
    },
    controller: function () {
      this.$onInit = function () {
        this.parent.foo(); // 'Foo from parent!'
      };
    },
    ...
  });

Let’s now bind this.state inside childComponent, and assign the result of the inherited this.parent.foo(); call:

angular
  .module('app', [])
  ...
  .component('childComponent', {
    require: {
      parent: '^parentComponent'
    },
    controller: function () {
      this.$onInit = function () {
        this.state = this.parent.foo();
      };
    },
    template: `
      <div>
        Component! {{ $ctrl.state }}
      </div>
    `
  });

Altogether now:

angular
  .module('app', [])
  .component('parentComponent', {
    transclude: true,
    template: `
      <div ng-transclude></div>
    `,
    controller: function () {
      this.foo = function () {
        return 'Foo from parent!';
      };
    }
  })
  .component('childComponent', {
    require: {
      parent: '^parentComponent'
    },
    controller: function () {
      this.$onInit = function () {
        this.state = this.parent.foo();
      };
    },
    template: `
      <div>
        Component! {{ $ctrl.state }}
      </div>
    `
  });

document.addEventListener('DOMContentLoaded', function () {
  angular.bootstrap(document, ['app']);
});

Live output:

About the author

Todd Motto

GDE Google Developer Expert

Todd is the Founder of Ultimate Courses. With a passion for Angular, TypeScript and JavaScript, Todd leads the online courses creation and has written hundreds of articles on front-end web development and beyond. He specialises in breaking down complex topics and understands the critical mission of learning new technology fast, comprehensively and the right way.

Love the post? Share it!

Lots of time and effort go into all our blogs, resources and demos,
we'd love it if you'd spare a moment to share them!

Start learning AngularJS now!

Get started today and join over 50,000 developers.