Javascript 当注入服务上的值更新时,如何更新AngularJS(使用TypeScript)控制器中的值

Javascript 当注入服务上的值更新时,如何更新AngularJS(使用TypeScript)控制器中的值,javascript,angularjs,typescript,Javascript,Angularjs,Typescript,目前,我正试图从Actionscript的背景中学习Typescript和AngularJS。我一直在玩一些代码实验,van通常实现了我想要的,但并不总是以我想要的方式 目前我有以下代码: export class CountingService { countScope = { count : 0 }; public increment() { this.countScope.count++; } } export class PageCon

目前,我正试图从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>

计数{{page.localCount}}/{{page.countScope.Count}
当我在视图之间切换时,localCount总是重置为零,但服务的countScope中的计数不会重置,而是由每个不同的控制器递增

这是可行的,但有点乱。我必须让非类型化的localScope四处浮动,视图需要了解countScope对象的内部结构,并绑定到page.countScope.count,而不是像page.globalCount这样的内容

在Actionscript中,我将在控制器上设置只读。每次值更改时,服务都会调度一个事件,控制器将侦听该事件,然后更新它自己的属性,然后更新视图

我的问题是,实现我在这里所做的事情的最佳实践方式是什么,它不需要视图了解非类型化对象的内部。 我很确定公共获取者不存在,但我可以发送并监听事件吗


非常感谢

简短回答:服务是单例的,即构造函数只调用一次。如果您想重置它,您可以从控制器的构造函数中执行此操作

this.service.countScope.count=0

笔记 我看到了很多我不喜欢的代码示例。但我相信这只是一个样本,所以不要把它当作个人冒犯;)

  • 没有名为
    service
    的服务。称之为
    countService
  • 服务上没有成员
    countScope
    。只需使用
    计数
    。并且不要将
    countScope
    复制到当前控制器。只需使用
    this.countService.count
更新 这个问题的根源是,当服务中的值发生更改时,如何更新html中显示的值


由于您将控制器设置为
page
page.service
是一种简单的
{{page.service.countScope.count}}
将显示计数。

这是答案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(这里的问题:)

约翰-这就是你的提议吗?如果有人对这个答案提出赞成和反对的意见,我将非常感激。
我将把这个标记为答案,因为我认为这是我开始时想要的答案。

这是答案2,我认为这是PSL想要的(或类似的东西)

接口计数回调
{
家长:任何;
回调:(值:number)=>void;
}
导出类计数服务
{
private _observer回调:Array=[];
私有服务计数:数字=100;
公共增量()
{
这个;
这个。notifyObservators();
}
公共注册表ObserverCallback(callbackParent:any,callbackFunction:(值:number)=>void)
{
var callback:CountingCallBack={parent:callbackParent,callback:callbackFunction};
this.\u observer callbacks.push(callback);
this.updateObserver(回调);
}
私人观察员()
{
forEach(this.\u observer回调,this.updateObserver,this);
}
私有更新观察服务器(回调:CountingCallBack)
{
callback.callback.apply(callback.parent,[this.\u serviceCount]);
}
}
导出类页面控制器
{
构造函数(专用计数服务:计数服务)
{
countingService.registerObserverCallback(this,this.updateLocal);
}
localCount:number=0;
serviceCount:编号;
公共增量()
{
this.countingService.increment();
这是.localCount++;
}
私有updateLocal(newValue:number)
{
this.serviceCount=newValue;
}
}
我很高兴能够实现这一点,因为我现在了解了函数接口语法的工作原理(我非常喜欢它),并且我成功地解决了控制器上updateLocal函数中的“this”范围问题

这个解决方案不需要注入$scope,这很好,但我发现回调实现相当混乱。我不喜欢将控制器和控制器上的函数传递给服务来添加回调。 我想我可以创建一个接口,ICountListener或其他什么,然后将其传递给服务,然后在控制器上调用updateCount。那样会更整洁一些,但还是不太好。 有没有比这更简洁的方法来设置回调

这段代码的最大问题(也是不应该使用它的原因)是它造成了内存泄漏。如果继续切换视图,控制器将永远不会被清理,因此内存中还有许多控制器,所有控制器都会响应更新的计数。
清理回调和取消注册回调相对容易,但这可能涉及注入$scope,然后监听销毁事件(我不知道怎么做,但我认为这在上面的评论中已经讨论过了)。

最后回答三个问题。我做的
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;
    }
}
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++;
    }
}
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++;
    }
}