ngmodel 更改时未触发角度日期过滤器

Posted

技术标签:

【中文标题】ngmodel 更改时未触发角度日期过滤器【英文标题】:Angular date filter not triggerd when ng-model has changed 【发布时间】:2017-05-27 15:38:51 【问题描述】:

我的 AngularJS 有一个问题,我似乎无法解决,因为我不知道自己做错了什么。


版本

AngularJS:1.6.1

角材料:1.1.1


问题

我正在使用 AngularJS 组件和过滤器构建一个日期时间选择器。 当我单击显示的日期(通过 $ctrl.model | date:'dd-MM-yyyy HH:mm' u 格式化)时,会打开一个带有自定义日期时间选择器的 Angular-material 弹出窗口,并显示一些更改日期的选项。用户单击“确认”后,日期将传递给我的组件(打开对话框的组件)并将新日期分配给模型this.model = newDate.getMomentDate();。在此之后,我希望查看日期也将被更新和格式化。然而它只是更新而不是格式化。

预期结果: 28-02-2016 00:00u

结果: 2016 年 2 月 28 日星期日 00:00:57 GMT+0100u


使用过的组件

为了实现这个功能,我使用了一些角度组件:

我的应用代码中的一个组件 (time.component.ts) 显示内容的 html 文件 (time.html) 将时间 ( $ctrl.model | date:'dd-MM-yyyy HH:mm' u) 转换为 time.html 并管理对话框 (datetimepicker.ts) 的组件 包含模型的 HTML 文件 - 嵌入到 time.html (datetimepicker.html) 中 管理对话框的控制器 (datetimepickerdialog.controller.ts) 带有对话框的 html 文件 (datetimedialog.html) 保存对话框信息的模型 (DateTimePickerModel.ts)


time.html

<date-time-picker title="pick your time"
                  model="$ctrl.time.meeting">
</date-time-picker>

datetimepicker.component.ts

绑定

bindings: 
    model: "=",  //Angular ng-model is automatically updated this way
    title: "@?"
,
transclude: true,
controller: DateTimePickerController

选择器回调

showPicker(): void 
     this.$mdDialog.show(this.datePickerDialog).then((newDate: DateTimePickerModel) => 
         this.model =  newDate.getMomentDate();
     , function () 
         //Cancel
      );

datepicker.html

<md-button ng-click="$ctrl.showPicker()" aria-label="open dialog">
     $ctrl.model | date:'dd-MM-yyyy HH:mm' u
</md-button>

DateTimePickerModel.ts

export class DateTimePickerModel 
    constructor(public day: string,
                public month: string,
                public year: string,
                public hour: string,
                public minute: string,
                public second: string) 
        

     /**
      * Returns the number of days of the month
      * @return number
      */
      getDaysInMonth(): number 
         return moment(this.year + '-' + this.month).daysInMonth();
      

     /**
      * Formats the property values to a moment date
      * @return Moment
      */
     getMomentDate(): Moment 
        return moment(
            this.year + "-" + this.month + "-" + this.day + "T" +
            this.hour + ":" + this.minute + ":" + this.second,
            moment.ISO_8601);
      

我省略了 datetimepickerdialog.controller.ts,因为 DateTimePickerModel 的一个实例被传递给控制器​​,它与 2-way-binding 或 ng-model 无关(我不希望有该控制器中可能导致问题的任何内容)。


我试过了

我尝试使用$scope.$apply(),因为我预计 Angular 没有看到变化。但是使用$scope.$apply() 我得到错误'Digest is already running'

我还尝试用单向绑定 ("&lt;") 替换组件的双向绑定 ("="),并使用函数将日期返回到 time.component.ts。然后,在time.component.ts 中,我将使用新日期更新ng-model。然而,这给了我同样的结果。

我找到了一个可行的解决方法,但这违背了 Angular 过滤器的全部目的。为此,我正在通过 get 方法操作控制器内部的模型。当发现更改时,这也有效并更新。但是我用视图操作污染了我的控制器。 (我不建议这样做!)

datetimepicker.component.ts

/**
 * Formats the model and return the formatted version.
 * - An Angular filter didn't work. It was somehow only called once, if the model changed it didn't format it -
 * @return string
 */
get formattedModel(): string 
    return moment(this.model).format('DD-MM-YYYY HH:mm');

datetimepicker.html

<md-button ng-click="$ctrl.showPicker()" aria-label="open dialog">
     $ctrl.formattedModel u
</md-button>

我想不出任何其他选项,因为 Angular 在每个 $digest 循环中运行页面上的每个过滤器,因为它不知道 ng-model 对哪些过滤器有效。 (每个更改都可能对页面产生影响,因此需要重新评估每个过滤器,每个周期)。

谁能帮帮我?

【问题讨论】:

虽然很多人未能提供足够详细的信息来获得他们需要的帮助,但您已经走到了另一个极端。您提供了太多信息,我没有时间阅读或使用所有信息。创建一个 plunker 并链接到它。 我同意你的观点,我应该使用 plunker。但问题是我使用的是 TypeScript 并且无法运行。我需要使用 javascript,但这是已编译且非常不可读的。关于我应该如何创建它的任何建议? Plunker 支持 1.5x + TS 【参考方案1】:

这是非常笼统的,因为您的问题非常详细。

首先,Angular 1.6 与 Material 1.1.1 尚不兼容,所以我将开始尝试使用 Angular 1.5 进行所有这些操作,看看这是否不能解决您的问题。 https://github.com/angular/material/issues/10111

其次,如果您正在制作使用模型的组件,请考虑遵循直接使用 ng-model 的模式,如下所述:https://docs.angularjs.org/api/ng/type/ngModel.NgModelController

第三,为什么不通过测试来隔离具体问题,然后你就会知道它是在组件中还是与你使用模态的方式有关。例如,用材料日期时间选择器替换您的时间选择器组件。如果这有效,那么您就知道问题出在您的组件中,与模态无关。

【讨论】:

1) 我从组件中删除了 Angular-material(改用简单的 html 标签)得到了同样的错误,所以不是这样。 2)我同意你关于 ng-model 的观点,但这意味着我们必须重构很多东西(大型应用程序并且从不知道模式)。将来要考虑的事情。 3) 我的代码与 Angular-material 组件非常不同,所以很遗憾我不能简单地替换它并使用相同的绑定和东西。

以上是关于ngmodel 更改时未触发角度日期过滤器的主要内容,如果未能解决你的问题,请参考以下文章

在路由更改上使用过滤器时未渲染路由模型

ngModel更改时如何解决select中没有值?

如何更改角度 ui-bootstrap 日期选择器的格式

在路径更改时使用过滤器时未呈现路径模型

剑道列过滤器内的角度材料日期选择器问题

访问表单:在文本框中捕获日期更改