1

I've got the following code, where I expect the content of the property variable to be displayed in the page. I read a couple of posts and tried to find out what I'm doing wrong, but couldn't find the error. Here is the code:

namespace testWeb.about {
    class AboutComponent implements ng.IComponentOptions {
        templateUrl = "scripts/components/about/about.html";
        controller = AboutController;
        bindings: any;

        constructor() {
            this.bindings = {
                awesomeThings : '<',
                property : '<'
            };
        }
    }

    interface IAboutController {
        awesomeThings: Array<string>;
        property: string;
    }

    export class AboutController implements IAboutController, ng.IComponentController {
        awesomeThings: Array<string>;
        property: string;

        constructor() {
            this.awesomeThings = [
                "one",
                "two",
                "three"
            ];
            this.property = "123";
        }
    }
    angular.module("test_web")
        .component("about", new AboutComponent())
        .config(($stateProvider) => {
            "ngInject";
            $stateProvider
                .state("about", {
                    url: "/about",
                    template: `<about></about>`
                });
        });
}

Whether <span ng-repeat="dd in $ctrl.awesomeThings">{{dd}}</span> nor <span class="as">{{$ctrl.property}}</span> gets displayed.

<span ng-repeat="dd in $ctrl.awesomeThings">{{dd}}</span>
<span class="as">{{$ctrl.property}}</span>
<p>123</p>
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
N.Zukowski
  • 600
  • 1
  • 12
  • 31

1 Answers1

1

This behaviour is caused by disabled pre-assigned bindings in Angular 1.6.

In 1.5, this.property = "123" overwrites initial binding value, even if it was provided.

In 1.6, the binding is assigned after constructor call. If a value for the binding is not provided, property is assigned to undefined.

To prevent this and provide the desired behaviour bindings should be marked as optional:

this.bindings = {
    awesomeThings : '<?',
    property : '<?'
};

Alternatively, initial values can be assigned in $onInit hook, this allows to ignore falsy initial values from bindings for example:

constructor() {}

$onInit() {
    this.awesomeThings = this.awesomeThings || [
        "one",
        "two",
        "three"
    ];
    this.property = this.property || "123";
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Should I use `$onInit` when optional bindings not working? Trying to create some dynamic menu with `ng-repeat` in the initial component, but cannot get it work. – N.Zukowski Apr 19 '17 at 07:46
  • Yes, this is how it is supposed to work, all initialization code goes to $onInit (which is an an alternative to directive pre-link function), unless it is known that code should be in constructor. For legacy components that are not ready for 1.6 see also https://toddmotto.com/angular-1-6-is-here#re-enabling-auto-bindings . ng-repeat has weird timing, so if the problem persists even with $onInit, it may be specific to ng-repeat . – Estus Flask Apr 19 '17 at 12:50