2

I would like to create a left hand menu component which displays different menu structure depending on the string it gets via binding.

For example:

<left-hand-menu-component module='abc'></left-hand-menu-component>

Then it shows only the abc module's menu structure. In order to achieve that the component controller must be able to work with the data comes trough bindings and make the necessary service calls.

I have been googling around for a while how to achieve this and I have find this and this posts and this posts. The example available at Angular documentation is too simple.

I have put together the example's code above and that part is missing when the controller can work with the value coming trough bindings.

It is even possible? Or it is rather a directive than a component?

Do you know example where it is displayed, blog entry or any source?

The two console.log in the controller constructor write out 'undefined' as result.

Component:

module qa.gonogo {
    "use strict";

    export class LeftHandMenuComponent implements ng.IComponentOptions {


        public transclude: boolean = false;
        public controller: Function = LeftHandMenuComponentController;
        public controllerAs: string = "vm";
        public templateUrl: string = "app/content/lefthandmenu/leftHandMenuComponentTemplate.html";
        public bindings: any;

        constructor() {
            this.bindings = {
                module: '<'
            }
        }
    }

    angular
        .module("goNoGo")
        .component("gonogoLefthandmenuComponent", new LeftHandMenuComponent());

}

Controller:

export class LeftHandMenuComponentController implements ILeftHandMenuComponentController {

        menuStructure: IMenuStructure[];
        closeOthers: boolean = true;

        static $inject = [];

        constructor(public module: string) {
            console.log('binding', module);
            console.log('binding2', this.module);
        }

        public $onInit = (): void => {
            this.populateMenuStructure();
        }

Route.

$stateProvider
            .state("bfts",
                <ng.ui.IState>{
                    url: "/bfts",
                    views: <any>{
                        "leftHandMenu": <ng.ui.IState>{
                            template: "<gonogo-lefthandmenu-component module='bfts'></gonogo-lefthandmenu-component>"
                        },
                        "content": <ng.ui.IState>{
                            template: "bfts content"
                        }
                    }
                });
Community
  • 1
  • 1
AndrasCsanyi
  • 3,943
  • 8
  • 45
  • 77
  • have you tried defining properties in the controller class with the names of the bound properties? – toskv Jun 26 '16 at 18:31
  • Not clear what problem you face. Yes, it's possible. Just move http calls to service. – dfsq Jun 26 '16 at 18:31
  • the first post you linked has an example of what you need in the FacebookIntegrationController with the settings property. – toskv Jun 26 '16 at 18:32
  • @toskv: I have tried in that way, but no success. I have attached the code. – AndrasCsanyi Jun 26 '16 at 18:45

1 Answers1

2

The bindings are available in the controller scope, so this.module must work.

I reproduced your code in a plnkr and found following errors.

  1. The main problem is that you use a "<" binding, which is a one-way binding. So it tries to access the "btfs" variable which is not defined in your scope, therefore undefined is absolutely correct output. To use a string use "@" see https://docs.angularjs.org/guide/component

    constructor() { this.bindings = { module: '@' } }

  2. dont inject the module var. just define it in your controller to satisfy typescript compiler.

    public module: string;

  3. you dont need controllerAs. The templates automatically gets the scope injected via $ctrl, see my example at medium. but not sure if thats critical

  4. as I described in my post its always a good idea to put angular.module calls at the bottom of the source file

modified code:

angular.module('goNoGo', []);


class LeftHandMenuComponent implements ng.IComponentOptions {


    public transclude: boolean = false;
    public controller: Function = LeftHandMenuComponentController;
    //public controllerAs: string = "vm";
    public template: string = "<div>module :{{$ctrl.module}}</div>";
    public bindings: any;

    constructor() {
        this.bindings = {
            module: '@'
        }
    }
}



class LeftHandMenuComponentController {

  menuStructure: IMenuStructure[];
  closeOthers: boolean = true;
  public module: string;

  static $inject = [];

  constructor() {
      console.log('binding2', this.module);
  }

  //public $onInit = (): void => {
    //  this.populateMenuStructure();
}

angular
    .module("goNoGo")
    .component("gonogoLefthandmenuComponent", new LeftHandMenuComponent());

angular.element(document).ready(function () {
  angular.bootstrap(document, ['goNoGo']);
});

you can play around in plnkr http://plnkr.co/edit/TVI9l8

Aco Mitevski
  • 353
  • 2
  • 9
  • Thanks for your help! I really appreciate it! Just for the record: yes, `@` was one of the mistakes I took. The another one was that, the controller was in a separated file. Once I put them in the same file the component started to work as I expected. I left the `controllerAs` there, it also works fine. I like this way. – AndrasCsanyi Jun 29 '16 at 05:48