网站搜索

angularjs - Typescript 构造函数参数在方法中未定义


我正在努力理解如何将 Typescript 和 Angularjs 一起使用。我已经阅读了几篇博客文章和两个项目的文档,但还是没有掌握。

我有一个 Angular 控制器,它依赖两个对象,$scope 和我写的一个名为 greetingService 的服务。我已经定义了一个主应用的 Angular 模块,并将该控制器和服务附加到它上面。我在 TypeScript 构造函数中有日志语句,以便在浏览器中检查这些依赖。在控制器和自定义服务的构造函数中,依赖注入都是正确的。然而,在控制器中,当我尝试使用某个依赖时,它是未定义的。我认为这段代码片段比我自己解释得更能说明问题。

declare var angular;

module App.Services {
    export class GreetingService {

        constructor(private $http) {
            console.log("In greeting service constructor");
            console.log($http);
        }

        getGreetingsPromise() {
            return this.$http.get('/greetings.json');
        }
    }
}

module App.Controllers {
    export class GreetingController {

        static $inject = ['$scope', 'greetingService'];
        constructor(public $scope, public greetingService: App.Services.GreetingService) {
            this.$scope.greeting = "This will be a greeting.";
            this.$scope.greet = this.greet;

            console.log(greetingService); // this is defined and looks right
        }

        greet(language: string) {
            console.log("Greeting...");
            console.log(this.$scope); // this is undefined
            console.log(this.greetingService); // this is undefined
            var greetingPromise = this.greetingService.getGreetingsPromise();
            greetingPromise.then(data => this.$scope.greeting = data[language]);
        }
    }
}


var mainApp = angular.module('mainApp', []);
mainApp.controller('greetingController', ['$scope', 'greetingService', App.Controllers.GreetingController]);
mainApp.service('greetingService', App.Services.GreetingService);

这里是 Angular 模板(它正确显示了在构造函数中初始化的“这将是一个问候”)。

<div class="jumbotron">
    <div ng-controller="greetingController">
        <p class="lead">{{greeting}}</p>
        <button ng-click="greet('english')">Greet me</button>
    </div>
</div>

答案#1

这一行:

this.$scope.greet = this.greet

就是问题所在。你只是将函数引用复制到作用域属性中,当它使用作用域调用时,this 不会是控制器实例,它由调用者决定(在你的情况下,当从模板调用 greet 函数时,this 应该是作用域本身),绑定函数除外。一个快速的解决方法是使用 function.bind。也就是 this.$scope.greet=this.greet.bind(this),通过它你创建了一个绑定函数,函数引用绑定到控制器实例。你也可以使用箭头函数并将其作为引用分配,这将强制 TypeScript 将任何 this 转换为缓存变量 _this:

   greet = (language: string) => {
        console.log("Greeting...");
        console.log(this.$scope); // this is undefined
        console.log(this.greetingService); // this is undefined
        var greetingPromise = this.greetingService.getGreetingsPromise();
        greetingPromise.then(data => this.$scope.greeting = data[language]);
    }

理想情况下,如果你使用 controller As(前提是你的 Angular 支持,如果不支持,强烈建议升级)语法,而不是直接使用 scope,你就不需要做所有这些。

即:

export class GreetingController {
    greeting :string;

    static $inject = ['greetingService'];

    constructor(public greetingService: App.Services.GreetingService) {
        this.greeting = "This will be a greeting.";
    }

    greet(language: string) {
        var greetingPromise = this.greetingService.getGreetingsPromise();
        greetingPromise.then(data => this.greeting = data[language]);
    }
}

和

<div class="jumbotron">
    <div ng-controller="greetingController as vm">
        <p class="lead">{{vm.greeting}}</p>
        <button ng-click="vm.greet('english')">Greet me</button>
    </div>
</div>