为什么angularjs Digest使用date getter函数进入无限循环

时间:2021-06-06 08:47:00

I have a DTO object which has a Date parameter. I am wrapping this Dto in a view model object the properties of which I am then binding in my view to a label.

我有一个DTO对象,它有一个Date参数。我将此Dto包装在视图模型对象中,然后我将视图中的属性绑定到标签。

<label class="form-control">{{controller.ViewModel.Date}}</label>

In the view model I have a getter thus. (I am using TypeScript)

在视图模型中,我有一个吸气剂。 (我正在使用TypeScript)

public get Date(): Date {
    return new Date(Date.parse(this.dto.Date));
    //return moment(this.dto.Date).toDate();
}

the emitted JavaScript:

发出的JavaScript:

Object.defineProperty(ViewModel.prototype, "Date", {
    get: function () {
        return new Date(Date.parse(this.dto.Date));
    },
    enumerable: true,
    configurable: true
});

I believe that the reason because I am creating a new Date in the getter and angular thinks that this means the dates are always new and it keeps getting the date until the model stabilises, thus causing an infinite loop.

我相信原因是因为我在getter和angular中创建一个新的Date认为这意味着日期总是新的并且它会一直保持日期直到模型稳定,从而导致无限循环。

Why is angular doing this?
Why does it keep calling the getter over and over, what is wrong with just calling it once?
Can I tell angular to just call the getter once and accept the value it is given?

为什么棱角分明这样做?为什么它一遍又一遍地调用getter,只调用一次有什么问题?我可以告诉角度只是调用一次吸气剂并接受它给出的值吗?

2 个解决方案

#1


2  

If you are on a high enough version, you could try a one time binding. Follow the instructions here: https://docs.angularjs.org/guide/expression#one-time-binding

如果你的版本足够高,你可以尝试一次性绑定。按照此处的说明操作:https://docs.angularjs.org/guide/expression#one-time-binding

You are basically right with your assumption that angular thinks the dates are always new. You are changing the value with the evaluation in your getter and angular's dirty checking and watches triggers another digest.

你基本上对你的假设是正确的,即angular认为日期总是新的。您正在使用getter和angular的脏检查中的评估来更改值,而watch会触发另一个摘要。

Could you also try parsing the date ahead of time?

您是否也可以提前解析日期?

#2


2  

I found an way round this as follows:

我找到了一个方法如下:

posting only the typescript as it is more readable:

仅发布打字稿,因为它更具可读性:

 public DisplayDate: string = new Date(Date.parse(this.dto.TxDate)).toLocaleDateString();
    public get TxDate(): Date {

        let txDate = new Date(Date.parse(this.dto.TxDate));
        if (this._txDate === null && this._txDate != txDate)
            this._txDate = txDate;
        return this._txDate;
    }
    public set TxDate(value: Date) {
        this.dto.TxDate = value.toISOString();
        this._txDate = value;
        this.DisplayDate = this._txDate.toLocaleDateString();
    }
    private _txDate: Date = null;

This appears to give me what I need. The Display date is bound to a visible label so that I can get the display format I want and the TxDate is bound to a hidden form date-picker control This way it all seems to work. And I can keep my Dto date in ISO8601 format.

这似乎给了我我需要的东西。显示日期绑定到可见标签,以便我可以获得我想要的显示格式,并且TxDate绑定到隐藏的表单日期选择器控件这样一切似乎都有效。我可以保持我的Dto日期为ISO8601格式。

#1


2  

If you are on a high enough version, you could try a one time binding. Follow the instructions here: https://docs.angularjs.org/guide/expression#one-time-binding

如果你的版本足够高,你可以尝试一次性绑定。按照此处的说明操作:https://docs.angularjs.org/guide/expression#one-time-binding

You are basically right with your assumption that angular thinks the dates are always new. You are changing the value with the evaluation in your getter and angular's dirty checking and watches triggers another digest.

你基本上对你的假设是正确的,即angular认为日期总是新的。您正在使用getter和angular的脏检查中的评估来更改值,而watch会触发另一个摘要。

Could you also try parsing the date ahead of time?

您是否也可以提前解析日期?

#2


2  

I found an way round this as follows:

我找到了一个方法如下:

posting only the typescript as it is more readable:

仅发布打字稿,因为它更具可读性:

 public DisplayDate: string = new Date(Date.parse(this.dto.TxDate)).toLocaleDateString();
    public get TxDate(): Date {

        let txDate = new Date(Date.parse(this.dto.TxDate));
        if (this._txDate === null && this._txDate != txDate)
            this._txDate = txDate;
        return this._txDate;
    }
    public set TxDate(value: Date) {
        this.dto.TxDate = value.toISOString();
        this._txDate = value;
        this.DisplayDate = this._txDate.toLocaleDateString();
    }
    private _txDate: Date = null;

This appears to give me what I need. The Display date is bound to a visible label so that I can get the display format I want and the TxDate is bound to a hidden form date-picker control This way it all seems to work. And I can keep my Dto date in ISO8601 format.

这似乎给了我我需要的东西。显示日期绑定到可见标签,以便我可以获得我想要的显示格式,并且TxDate绑定到隐藏的表单日期选择器控件这样一切似乎都有效。我可以保持我的Dto日期为ISO8601格式。