How to angularjs app.service and $q in typescript

1.3k views Asked by At

I am Very new to typescript and angular Js . I have am not able to find correct answer , my code is given below:

export class SidenavController {
static $inject = ['$scope', '$mdSidenav'];
     constructor(private $scope: any,private $mdSidenav: any) {

     }
toggleSidenav(name: string) {
    this.$mdSidenav(name).toggle();
     }
  loadHelpInfo() {
    this.helpService.loadAll()
      .then(function(help) {
        this.$scope.helpInfo = [].concat(help);
        this.$scope.selected = this.$scope.helpInfo[0];
      })
  }
  selectHelpInfo(help) {
    this.$scope.selected = angular.isNumber(help) ? this.$scope.helpInfo[help] : help;
    this.$scope.toggleSidenav('left');
  } 

}
app.service('helpService', ['$q', function($q) {
  var helpInfo = [{
      name: 'Introduction',
      content: '1 '
  }, {
      name: 'Glossary',
      content: '2'
  }, {
      name: 'Log In',
      content: '3'
      }, {
      name: 'Home Page',
      content: '4'
  }];

  return {
      loadAll: function() {
          return $q.when(helpInfo);
      }
  };
}]);

In the above code I want to use helpService to load the details on the screen. I am getting following error while executing : app/components/sidenav/sidenav-controller.ts(10,10): error TS2339: Property 'helpService' does not exist on type 'SidenavController'. I am not sure how to use services in typescript. Also if required I have done codepen version of the angular :

http://codepen.io/snehav27/pen/JdNvBV

Basically I am trying to do typescript version of above snippet

1

There are 1 answers

6
PSL On BEST ANSWER

You need to inject helpservice and set it in your constructor argument.

     static $inject = ['$scope', '$mdSidenav', 'helpService'];
     constructor(private $scope: any,private $mdSidenav: any, private helpService:any) {

     }

otherwise Typescript does not know what are you referring to as this.helpService, even without TS it will result in an error when you try to do this.helpService.loadAll with "cannot access loadAll of undefined" error or similar.

Also use Arrow operator to resolve lexical scoped this @

  this.helpService.loadAll()
  .then((help) => { //<-- here
    this.$scope.helpInfo = [].concat(help);
    this.$scope.selected = this.$scope.helpInfo[0];
  });

otherwise it will result in another error since this wont be the controller instance inside the callback.

You may also create a typing for helpService for better usage and reduce any typos.

export interface IHelpService{
  loadAll():ng.IPromise<Array<HelpInfo>>; //use specific typing instead of any
}

export interface HelpInfo{
  name:string;
  content:string;
}

class HelpService implements IHelpService{
    private _helpInfo:Array<HelpInfo> = [{
      name: 'Introduction',
      content: '1 '
  }, {
      name: 'Glossary',
      content: '2'
  }, {
      name: 'Log In',
      content: '3'
      }, {
      name: 'Home Page',
      content: '4'
   }];

    static $inject = ['$q'];
    constructor(private $q:ng.IQService){
    }

    loadAll(){
       return this.$q.when(this._helpInfo);
    }

 }

angular.module('HelpApp').service('helpService', HelpService);

and

 constructor(private $scope: any,private $mdSidenav: any, private helpService:IHelpService) {

It would also be better to use controller as syntax with Typescript class defn and totally get rid of attaching properties to scope. What you have right now is half baked (functions attached to controller instance and some properties to scope).

export class SidenavController {

    helpInfo:Array<HelpInfo>;
    selected:HelpInfo; 

    static $inject = ['$mdSidenav', 'helpService'];
    constructor(private $mdSidenav: any, private helpService:IHelpService) {}

     toggleSidenav(name: string) {
        this.$mdSidenav(name).toggle();
     }

     loadHelpInfo() {
        this.helpService.loadAll()
          .then((help) => {
            this.helpInfo = [].concat(help);
            this.selected = this.helpInfo[0];
          })
      }

      selectHelpInfo(help) {
        this.selected = angular.isNumber(help) ? this.helpInfo[help] : help;
        this.toggleSidenav('left');
      } 

}

and in your view:

<body layout="column" ng-controller="AppCtrl as vm">

and refer to the properties and methods prefixed with vm (You could use any alias, i just use vm). Example (you should be able to figure out rest):-

<md-item ng-repeat="it in vm.helpInfo">

<--- some code -->

 <md-button ng-click="vm.selectHelpInfo(it)" 
            ng-class="{'selected' : it === vm.selected }">