trex trex - 25 days ago 9
AngularJS Question

Get binded object inside component controller

Angular 1.6

I can't understand why I don't have access to the binded

self.widget
object in my component controller. The
console.log(self.widget);
prints
undefined
. But I get access to the
widget
object in template via
$ctrl.widget
, the widget works.

enter image description here

And I see the object in browser console when I do
angular.element($0).scope().$ctrl


Component:

import template from './templates/clock-widget.template.html';
import controller from './clock-widget.controller';

const clockWidget = {
bindings: {
widget: '<'
},
controller,
template
};

export default clockWidget;


Controller of the component:

import controller from './clock-widget.settings.controller.js';
import template from './templates/clock-widget.settings.template.html';

import 'angular-clock/dist/angular-clock.css';
import './style.css';

import timezones from './timezones';

const injectParams = ['$scope', '$timeout', '$uibModal'];
const ClockWidgetCtrl = function($scope, $timeout, $uibModal) {
const self = this;

self.gmtOffset = 2;
console.log(self.widget);

self.openSettings = function() {
$uibModal.open({
scope: $scope,
controllerAs: '$ctrl',
controller,
template,
resolve: {
widget: function() {
return self.widget;
}
}
});
};
};

ClockWidgetCtrl.$inject = injectParams;
export default ClockWidgetCtrl;


Component template:

<div class="box clock-widget">
<div class="box-header">
<h3>{{ $ctrl.widget.title }}</h3>
<div class="box-header-btns pull-right">
<a title="settings" ng-click="$ctrl.openSettings(widget)"><i class="glyphicon glyphicon-cog"></i></a>
<a title="Remove widget" ng-click="$ctrl.remove(widget)"><i class="glyphicon glyphicon-trash"></i></a>
</div>
</div> <!-- END box-header -->

<div class="box-content">
<b>{{$ctrl.widget.config.location.split('/')[1]}}</b>
<ds-widget-clock gmt-offset="$ctrl.gmtOffset" show-analog show-gmt-info></ds-widget-clock>
</div> <!-- END box-content -->
</div> <!-- END box -->

Answer Source

Directive/component template hasn't been compiled yet at the moment when a controller is constructed, and bindings aren't assigned to controller instance as well.

According to the reference,

After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller properties. You can access these bindings once they have been initialized by providing a controller method called $onInit, which is called after all the controllers on an element have been constructed and had their bindings initialized.

This behaviour is controlled by $compileProvider.preAssignBindingsEnabled:

Call this method to enable/disable whether directive controllers are assigned bindings before calling the controller's constructor. If enabled (true), the compiler assigns the value of each of the bindings to the properties of the controller object before the constructor of this object is called.

If disabled (false), the compiler calls the constructor first before assigning bindings.

The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.

All logic that is related to bindings and DOM should be placed inside $onInit or $postLink hook (newer alternatives to directive pre/post-link functions):

self.$onInit = function () {
    console.log(self.widget);
}