一般来说,在我的Angular / TypeScript应用程序中,我倾向于使用“控制器为”语法.
然而,对于我正在研究的CRUD屏幕,我发现自己偏离了这一点.因此我可以利用$watchCollection /检查更改等我发现自己使用了优秀的章节@baSarat here所建议的模式.即,在视频中(在Angular中以“控制器为”语法之前)@ baSarat在名为vm的$scope上创建一个表示控制器的变量.与在视图中使用“controller as vm”的方式相同,您仍然可以使用vm.myProperty / vm.myFunction()样式语法与模型进行交互.
所以,控制器看起来像这样:
module controllers { "use strict"; interface sageEditRouteParams extends ng.route.IRouteParamsService { id: number; } interface sageEditScope extends ng.IScope { vm: SageEdit; } class SageEdit { log: loggerFunction; sage: sage; title: string; private _hasChanges: boolean; static $inject = ["$routeParams","$scope","common","datacontext"]; constructor( private $routeParams: sageEditRouteParams,private $scope: sageEditScope,private common: common,private datacontext: datacontext ) { this.sage = undefined; this.title = "Sage Edit"; this.log = common.logger.getLogFn(controllerId); $scope.vm = this; $scope.$watchCollection("vm.sage",(newSage: sage,oldSage: sage) => { if (newSage && oldSage) { this._hasChanges = true; } }); this.activate(); } // Prototype methods activate() { var id = this.$routeParams.id; var dataPromises: ng.IPromise<any>[] = [this.getSage(id)]; this.common.activateController(dataPromises,controllerId) .then(() => { this.log("Activated Sage Edit View"); this.title = "Sage Edit: " + this.sage.name; }); } getSage(id: number) { return this.datacontext.sage.getById(id).then(data => { this.sage = data; this._hasChanges = false; }); } get hasChanges(): boolean { return this._hasChanges; } } var controllerId = "sageEdit"; angular.module("app").controller(controllerId,SageEdit); }
这样的观点:
<section class="mainbar" ng-controller="sageEdit"> <section class="matter"> <div class="container-fluid"> <div> <button class="btn btn-info" ng-click="vm.cancel()" ng-disabled="!vm.canSave"> <i class="fa fa-undo"></i>Cancel </button> <button class="btn btn-info" ng-click="vm.save()" ng-disabled="!vm.canSave"> <i class="glyphicon glyphicon-save"></i>Save </button> <span ng-show="vm.hasChanges" class="dissolve-animation ng-hide"> <i class="glyphicon glyphicon-asterisk text-info"></i> </span> </div> <div class="widget wgreen"> <div data-cc-widget-header title="{{vm.title}}"></div> <div class="widget-content form-horizontal"> <div class="form-group"> <label class="col-xs-12 col-sm-2">Name</label> <input class="col-xs-12 col-sm-9" ng-model="vm.sage.name" /> </div> <div class="form-group"> <label class="col-xs-12 col-sm-2">Username</label> <input class="col-xs-12 col-sm-9" ng-model="vm.sage.userName" /> </div> <div class="form-group"> <label class="col-xs-12 col-sm-2">Email</label> <input class="col-xs-12 col-sm-9" type="email" ng-model="vm.sage.email" /> </div> </div> </div> </div> </section> </section>
我把它放在一起似乎工作得很好,但我想把它放在那里并得到一些其他观点.在那儿:
>这种方法有任何缺点
>任何原因这都是个坏主意
>更好的选择?
我做了一点挖掘,但没有找到任何结论.
解决方法
魔术弦去除
对于
$scope.$watchCollection("vm.sage",oldSage: sage) => {
您还可以轻松实现重构:
$scope.$watchCollection(()=>this.sage,oldSage: sage) => {
在某些情况下,当您尝试观看foo.bar之类的内容时,foo仍未定义,您可以使用安全包装函数safeWatch(()=> this.foo.bar):
function safeWatch<T extends Function>(expression: T) { return () => { try { return expression(); } catch (e) { return null; } }; }
控制器与$scope.vm
Fron源代码:
https://github.com/angular/angular.js/blob/36831eccd1da37c089f2141a2c073a6db69f3e1d/src/ng/controller.js#L95
这正是角度为你做的事情. ie $scope.vm = instance(其中vm == indentifier)所以它们是等价的