【问题标题】:Typescript + Angular "controller as" Sidewaffle template doesn't work out of the boxTypescript + Angular “控制器作为” Sidewaffle 模板不能开箱即用
【发布时间】:2015-03-10 09:04:55
【问题描述】:

请原谅我后面的代码墙,但每个块只有一个小改动,每个改动都有注释。

我正在尝试使用 Sidewaffle 模板包附带的 Angular+Typescript“控制器作为”模板。这就是模板开箱即用的样子。我在这里对模板所做的唯一修改是 cmets、空格和将“app1”重命名为“app”:

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    controllerId: string; //This won't work...
    changeGreeting: () => void;
}
class testController implements ItestController {
    static controllerId: string = "testController"; //...because this is static.
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }
    changeGreeting() {
        this.greeting = "Bye";
    }
}
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', ($scope, $http, $resource) =>
        new testController($scope, $http, $resource)
    ]);

首先要注意的是,由于控制器类上的静态controllerId 成员和Icontroller 接口所需的controllerId 成员,它甚至无法编译。由于接口的成员需要在类的类型的实例端实现,所以这是行不通的。

这很烦人,但很容易解决,尽管这样做会丢失一些类型检查:

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    changeGreeting: () => void;
}
class testController implements ItestController {
    //we leave the static member on the class and remove the member
    //from the interface
    static controllerId: string = "testController";
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }
    changeGreeting() {
        this.greeting = "Bye";
    }
}
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', ($scope, $http, $resource) =>
        new testController($scope, $http, $resource)
    ]);

现在可以编译了,但问题是对app.controller() 的调用如何转换为javascript。不是直接将构造函数传递给app.controller(),而是封装在一个匿名函数中,我们最终得到的是构造函数中的构造函数:

var testController = (function () {
    function testController($scope, $http, $resource) {
        this.$scope = $scope;
        this.$http = $http;
        this.$resource = $resource;
        this.greeting = "Hello";
    }
    testController.prototype.changeGreeting = function () {
        this.greeting = "Bye";
    };
    testController.controllerId = "testController";
    return testController;
})();
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource',
    //Why won't this work? Why would we want to do this in the first place?
    function ($scope, $http, $resource) { 
        return new testController($scope, $http, $resource); 
    }
]);

现在,当我们尝试在视图中使用“controller as”语法时,Angular 找不到别名控制器——视图绑定到一个空对象。

据我所知,Typescript 模板应该如下所示:

interface ItestControllerScope extends ng.IScope {
    vm: testController;
}
interface ItestController {
    greeting: string;
    changeGreeting: () => void;
}
class testController implements ItestController {
    static controllerId: string = "testController";
    greeting = "Hello";

    constructor(private $scope: ItestControllerScope, private $http: ng.IHttpService, private $resource: ng.resource.IResourceService) {
    }

    changeGreeting() {
        this.greeting = "Bye";
    }
}
//Now we're passing the controller constructor directly instead of
//wrapping the constructor call in another constructor
app.controller(testController.controllerId,
    ['$scope', '$http', '$resource',testController]);

编译成这个javascript:

var testController = (function () {
    function testController($scope, $http, $resource) {
        this.$scope = $scope;
        this.$http = $http;
        this.$resource = $resource;
        this.greeting = "Hello";
    }
    testController.prototype.changeGreeting = function () {
        this.greeting = "Bye";
    };
    testController.controllerId = "testController";
    return testController;
})();

app.controller(testController.controllerId,
    ['$scope', '$http', '$resource', testController]);

效果很好。所以我有两个主要问题:

  1. 为什么要将控制器构造函数包装在 lambda 中以交给 Angular 的 controller() 方法,而不是直接交给构造函数?
  2. 为什么模板会在一个类上拥有一个静态成员,并试图通过该类实现的接口上的一个成员来强制执行该成员?

我唯一的猜测是,这两个问题在 Typescript 和 Angular 的早期版本组合中都不是问题,但我不知道,因为我对这两个版本都很陌生。我正在使用 Typescript v1.4 和 Angular v1.3.14

【问题讨论】:

  • 我似乎找不到插入模板的打字稿版本的方法,请帮忙?
  • 您的打字稿版本不依赖于已安装模板的版本。这取决于您安装的 Typescript 版本 + 项目中定义的版本号。
  • 对不起,我无法准确表达我的情况。我面临的是在插入元素对话框中根本找不到打字稿模板。但现在他们就像魔术一样在这里。我没有改变任何东西。也许只是我不够重视。还是谢谢。

标签: angularjs typescript typescript1.4 sidewaffle


【解决方案1】:

为什么你会想要将控制器构造函数包装在 lambda 中以交给 Angular 的 controller() 方法,而不是直接交给构造函数?

你不会的。我不https://www.youtube.com/watch?v=WdtVn_8K17E

为什么模板在一个类上会有一个静态成员,它试图用该类实现的接口上的一个成员来强制执行

关于controllerId: string; //This won't work... 在接口上拥有成员并使用类实现该接口意味着类的实例将拥有该成员。然而你想说的是这个类有这个成员。这不能通过实现接口来完成。

您可以通过其他方式确保这一点:

var mustHaveId:{controllerId:string};

class Fail{}
class Pass{static controllerId = "Pass"}

mustHaveId = Fail; // Error 
mustHaveId = Pass; // Pass

【讨论】:

  • 我同意你的观点,我只是不明白为什么 Sidewaffle 模板是这样构建的。当然,我的问题中第一个代码中的代码在某一时刻有效。
  • I answered my own question. 该模板必须在 Typescript v1.0 和 Angular v1.3 之前工作。
【解决方案2】:

查看source code on Github 会发现有问题的模板已“更新为与 Typescript 1.0 和 Angular 1.3 兼容”,因此结合以前版本的 Angular 和 Typescript 模板中的所有内容都必须有效在过去的某个时间。

我的两个问题在更新后的文件中得到了解决,所做的更改与我为使事情正常运行所做的更改相似。 Sidewaffle 模板包尚未相应更新。

更新:在撰写本文时,最新版本的 Sidewaffle 模板包括固定模板。

【讨论】:

  • 没有。 TypeScript 0.8(第一个版本)具有与 class 相同的语义,因此没有任何变化。 Angular 1.0 仍然使用new 调用控制器并支持$inject,所以没有任何改变。模板只是 JavaScript 开发人员错误地掌握了 TypeScript。
  • @basarat 您可能是对的,但该存储库是由一些非常聪明的人策划的。如果他们让这样的错误溜走,我会感到惊讶,尤其是这么长时间。在撰写本文时,这些更新仅在 17 天前进行。
  • @basarat 包括你!
  • 我对模板进行了一些额外的更改,以便它们可以与 Angular 一起使用,但仍然使用 TypeScript 类,Sayed 今天刚刚发布了新版本的 SideWaffle,因此现在应该解决这些问题。
猜你喜欢
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 1970-01-01
  • 2016-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
相关资源
最近更新 更多