我正在尝试改变我从简单javascript编写AngularJS应用程序到使用TypeScript作为预处理器的方式。
当涉及到范围方法调用时,我正在努力调和这两种方法。
为了便于说明,我们考虑常见的菜单用例;我想强调当前显示的特定菜单项。 HTML模板如下所示:
<ul class="nav navbar-nav">
...
<li ng-class="{active: isSelected('/page1')}"><a href="#/page1">Page 1</a></li>
...
</ul>
这预示着一个名为isSelected
的范围函数。使用老式的javascript编码,我&#39;把它写成:
$scope.isSelected = function(path) {
return $location.path().substr(0, path.length) == path;
}
这个匿名函数声明似乎并没有真正遵循更传统的TypeScript类模型。在打字稿中,我发现自己很想写这个:
export interface MenuScope extends ng.IScope {
isSelected(path: String): boolean;
}
export class MenuController {
location: ng.ILocationService;
scope: MenuScope;
constructor($scope: MenuScope, $location: ng.ILocationService) {
this.scope = $scope;
this.location = $location;
this.scope.isSelected = function(path) { return this.isSelected(path) }.bind(this);
}
isSelected(path: String): boolean {
return this.location.path().substr(0, path.length) == path;
}
}
在这种情况下,isSelected
属于控制器,而不是范围。这似乎是明智的。然而,&#34;链接&#34;范围和控制器之间仍然依赖于匿名方法。
更糟糕的是,我必须明确绑定this
的上下文,以确保我可以在this.location
的实现中编写isSelected()
来访问位置服务。
我从TypeScript中寻找的一个好处是更清晰的编写代码的方式。这种通过绑定匿名函数的间接似乎与此相反。
答案 0 :(得分:2)
您不应将$scope
作为变量存储在this
中,而是使用this
作为$scope
,执行此操作的方法是{ {1}}在构造函数的开头,现在该类的每个函数和变量都将成为$ scope的一部分。
您无法避免使用$scope.vm = this;
,因为这是TypeScript的语法。
顺便说一句,你应该使用$ inject来获取依赖项。
答案 1 :(得分:2)
这是一个带控制器和服务的简单应用程序。我在我的项目中使用这种风格:
/// <reference path="typings/angularjs/angular.d.ts" />
module App {
var app = angular.module("app", []);
app.controller("MainController as vm", Controllers.MainController);
app.service("backend", Services.Backend);
}
module App.Controllers {
export class MainController {
public persons: Models.Person[];
static $inject = ["$location", "backend"];
constructor(private $location: ng.ILocationService, private backend: Services.Backend) {
this.getAllPersons();
}
public isSelected(path: string): boolean {
return this.$location.path().substr(0, path.length) == path;
}
public getAllPersons() {
this.backend.getAllPersons()
.then((persons) => {
this.persons = persons;
})
.catch((reason) => console.log(reason));
}
}
}
module App.Services {
export class Backend {
static $inject = ["$http"];
constructor(private $http: ng.IHttpService) { }
public getAllPersons(): ng.IPromise<Models.Person[]> {
return this.$http.get("api/person")
.then((response) => response.data);
}
}
}
module App.Models {
export interface Person {
id: number;
firstName: string;
lastName: string;
}
}
controller as
语法注册到应用程序。因此,您在课堂中定义的所有内容都可以通过视图(控制器范围)中的vm
访问。我们在这里persons
,isSelected
和getAllPersons
。static $inject
string[]
注入每个注射剂,然后分别将它们添加为构造函数参数。在定义服务时,此角色也可用,并且可以进行修改。$scope
以访问范围特定的工具,例如$apply
,on
等。ng.IPromise<Model>
,然后返回response.data
以确保返回方法的类型只是实体,而不是http相关数据。答案 2 :(得分:1)
我们正在考虑类似的转换(例如从Javascript到Anglecript for Angular)。在我们开始实施时,有些事情(比如你的例子)看起来很奇怪。最简单的方法是使用controller as
语法。这样,您可以直接在控制器上公开方法。
<!-- use controller as syntax -->
<div ng-controller="MenuController as menu">
<ul class="nav navbar-nav">
...
<li ng-class="{active: menu.isSelected('/page1')}"><a href="#/page1">Page 1</a></li>
...
</ul>
</div>
这将允许您超越将范围的方法绑定回控制器上的方法的需要。我不喜欢这种方法:
class
这样熟悉的代码,以获得仍有空间的代码优化。请参阅Typescript Playground生成的继承代码(为您要扩展类的每个.js文件生成的扩展函数,除非您的引用是在点,可以缓存函数的原型以向其添加方法而不是每个方法的ClassName.prototype.method ...),但我离题另一种选择是不使用类,而是坚持强类型函数:
export function MenuController($scope: MenuScope, $location: ng.ILocationService): any {
$scope.isSelected = function(path:string): boolean {
return $location.path().substr(0, path.length) == path;
}
}
由于angular负责实例化控制器,因此返回类型any
无关紧要。但如果你的$ scope的方法有错字,你就会被抓住。
要解决此问题,您可以使用controller as
语法更进一步。下面的示例不会让您自己实际启动控制器(例如,新的MenuController($ location)会因only void function can be called with new keyword
而失败),但这可以忽略不计,因为angular会为您处理实例化。
export interface IMenuController {
isSelected(path: string): boolean;
}
export function MenuController($location: ng.ILocationService): IMenuController {
var self:IMenuController = this;
self.isSelected = function(path:string): boolean {
return $location.path().substr(0, path.length) == path;
}
// explicitly return self / this to compile
return self;
}
TL DR:我是编辑时检查类型的粉丝,并且喜欢使用类的概念。但是,我不认为它完全符合Angular 1.x模型。看起来这是为Angular2设计的。对Angular 1.x使用强类型函数。