Write AngularJS like a pro. Angularjs Icon

Follow the ultimate AngularJS roadmap.

$onInit and new require Object syntax in Angular components

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.

Angular Directives In-Depth eBook Cover

Free eBook

Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.

  • Green Tick Icon Observables and Async Pipe
  • Green Tick Icon Identity Checking and Performance
  • Green Tick Icon Web Components <ng-template> syntax
  • Green Tick Icon <ng-container> and Observable Composition
  • Green Tick Icon Advanced Rendering Patterns
  • Green Tick Icon Setters and Getters for Styles and Class Bindings

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']);
});

Thank you for reading!

Learn Angular the right way.

The most complete guide to learning Angular ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover