目前我正在努力学习来自Actionscript背景的Typescript和AngularJS。我一直在玩一些代码实验,而van通常会实现我想要的但不总是以我想要的方式实现!
目前我有这段代码:
export class CountingService
{
countScope = { count : 0 };
public increment()
{
this.countScope.count++;
}
}
export class PageController
{
constructor( private service : CountingService )
{
this.countScope = service.countScope;
}
public localCount : number = 0;
countScope;
public increment()
{
this.service.increment();
this.localCount++;
}
}
我有几个不同的视图,其中包含以下代码:
<div ng-controller="PageController as page">
<Button ng-click="page.increment()">Count {{page.localCount}}/{{page.countScope.count}}</Button>
</div>
当我在视图之间切换时,localCount总是重置为零,但来自服务的countScope中的计数不会重置,并且会被每个不同的控制器递增。
这有效,但有点乱。我必须让无类型的localScope浮动,视图需要知道countScope对象的内部结构并绑定到page.countScope.count而不是像page.globalCount。
在Actionscript中,我只能读取控制器。每次更改值时,服务都会调度一个事件,控制器会监听它,然后更新它自己的属性,然后更新视图。
我的问题是,实现我在这里做的事情的最佳实践方法是什么,不需要视图知道无类型对象的内部。 我很确定公共吸气剂不存在,但我可以发送和收听事件吗?
非常感谢
答案 0 :(得分:1)
最后回答三。我没想到这会起作用,但确实如此,恕我直言,这是迄今为止最好的解决方案。
它使用getter强制封装,不需要注入$ scope,也不用担心内存泄漏。
我欢迎任何批评指出我不知道的问题。
我唯一知道的是你需要启用ECMAScript 5,这意味着不支持IE 7和8。这对我来说很好。
export class CountingService
{
private _serviceCount : number = 100;
public increment()
{
this._serviceCount++;
}
get serviceCount() : number
{
return this._serviceCount;
}
}
export class PageController
{
constructor( private countingService : CountingService )
{}
private _localCount : number = 0;
get localCount() : number
{
return this._localCount;
}
get serviceCount() : number
{
return this.countingService.serviceCount;
}
public increment()
{
this.countingService.increment();
this._localCount++;
}
}
答案 1 :(得分:1)
这似乎非常适合反应库,正是我们所做的。我强烈建议你查看具有一些很棒功能的RxJs。 https://github.com/Reactive-Extensions/RxJS/tree/master/doc
https://www.youtube.com/watch?v=XRYN2xt11Ek
您使用Rx进行编码
export class CountingService {
//Create a stream of changes. When caller subscribe always give them the most recent value.
private rawCountStream = new Rx.Subject<number>();
public countStream : Rx.Observable<number>;
private count = 0;
constructor() {
this.countStream = this.rawCountStream.replay(1);
}
public increment() {
this.count++;
//Pump the value to callers.
this.rawCountStream.onNext(this.count);
}
}
export class PageController {
constructor(private service: CountingService) {
//Listen to the stream of changes.
service.countStream.subscribe(value => {
//do something
//IMPORTANT If you want angular to update the ui you will need to call $apply on a scope.
//RXJS has a scheduler for this so you look at that here.
//https://github.com/Reactive-Extensions/rx.angular.js
}
);
}
public localCount: number = 0;
public increment() {
this.service.increment();
this.localCount++;
}
}
答案 2 :(得分:0)
这是第1号答案,我认为John Kurlak正在讨论的方法是:
export class CountingService
{
serviceCount : number = 100;
public increment()
{
this.serviceCount++;
}
}
export class PageController
{
constructor( $scope, private service : CountingService )
{
this.serviceCount = service.serviceCount;
$scope.$watch( () => this.service.serviceCount, ( newValue : number, oldValue : number ) => this.updateLocal( newValue, oldValue ) );
}
localCount : number = 0;
serviceCount : number;
public increment()
{
this.service.increment();
this.localCount++;
}
private updateLocal( newValue : number, oldValue : number )
{
this.serviceCount = newValue;
}
}
这是有效的,我认为是我追求的那种解决方案。有些事情我不喜欢它。
我不喜欢将$ scope注入我的服务。它似乎是对我不应该需要的东西的额外依赖。 我也真的不喜欢可以通过任何东西更新并打破封装的公共成员。我想用getter解决这个问题,但我无法弄清楚如何更新到ECMAScript 5(问题:Targeting ES5 with TypeScript in IntelliJ IDEA 14)。
约翰 - 这就是你提出的建议吗?如果有人对优点和缺点评论这个答案,我将非常感激。 我将此标记为答案,因为我认为这是我开始时的目标。答案 3 :(得分:0)
这是答案2,我认为这是PSL所得到的(或类似的)
interface CountingCallBack
{
parent : any;
callback : ( value : number ) => void;
}
export class CountingService
{
private _observerCallBacks : Array<CountingCallBack> = [];
private _serviceCount : number = 100;
public increment()
{
this._serviceCount++;
this.notifyObservers();
}
public registerObserverCallback( callbackParent : any, callbackFunction : ( value : number ) => void )
{
var callback : CountingCallBack = { parent : callbackParent, callback : callbackFunction };
this._observerCallBacks.push( callback );
this.updateObserver( callback );
}
private notifyObservers()
{
angular.forEach( this._observerCallBacks, this.updateObserver, this );
}
private updateObserver( callback : CountingCallBack )
{
callback.callback.apply( callback.parent, [ this._serviceCount ] );
}
}
export class PageController
{
constructor( private countingService : CountingService )
{
countingService.registerObserverCallback( this, this.updateLocal );
}
localCount : number = 0;
serviceCount : number;
public increment()
{
this.countingService.increment();
this.localCount++;
}
private updateLocal( newValue : number )
{
this.serviceCount = newValue;
}
}
我很高兴我能够实现这一点,因为我现在已经了解了功能界面语法是如何工作的(而且我非常喜欢它)并且我设法通过&#39;这个&#39;来解决问题。控制器上的updateLocal函数中的范围问题。
这个解决方案不需要和$ scope注入,这很好,但我发现回调实现非常混乱。我不想将控制器和控制器上的功能传递给服务以添加回调。 我想我可以创建一个接口,ICountListener或其他东西,然后将其传递给服务,然后在控制器上调用updateCount。那会更整洁但仍然不那么好。 设置回调的方法是否比这更简洁呢?
此代码的最大问题(以及不应使用它的原因)是它会造成内存泄漏。如果继续切换视图,控制器永远不会被清理,因此内存中有许多控制器都响应更新的计数。 清理回调和取消注册回调会相对容易,但这可能涉及注入$ scope然后听取毁灭事件(我不知道如何做到这一点但我认为这是在在上面的评论中讨论。)
答案 4 :(得分:-1)
简短回答:服务是单例,即构造函数仅调用一次。如果要重置它,可以从控制器的构造函数中执行此操作。
this.service.countScope.count = 0
我看到很多我不喜欢的代码示例。但我确信它只是一个样本,所以不要将其视为个人冒犯;)
service
的服务。称之为countService
。 countScope
。只需使用count
即可。并且不要将countScope
复制到当前控制器。只需使用this.countService.count
这个问题的根源是当服务中的值发生变化时如何更新html中的显示值
由于您将控制器设为page
且page.service
是服务,因此{{page.service.countScope.count}}
只显示计数。