NgFor不使用Angular2中的Pipe更新数据

NgFor不使用Angular2中的Pipe更新数据

在这种情况下,我正在向视图中显示学生列表(数组)ngFor

<li *ngFor="#student of students">{{student.name}}</li>

每当我将其他学生添加到列表中时,它都会更新。

然而,当我给它一个pipefilter由学生的名字,

<li *ngFor="#student of students | sortByName:queryElem.value ">{{student.name}}</li>

在我在过滤学生姓名字段中输入内容之前,它不会更新列表。

这是plnkr的链接。

Hello_world.html

<h1>Students:</h1><label for="newStudentName"></label><input type="text" name="newStudentName" placeholder="newStudentName" #newStudentElem><button (click)="addNewStudent(newStudentElem.value)">Add New Student</button><br><input type="text" placeholder="Search" #queryElem (keyup)="0"><ul>
    <li *ngFor="#student of students | sortByName:queryElem.value ">{{student.name}}</li></ul>

sort_by_name_pipe.ts

import {Pipe} from 'angular2/core';@Pipe({
    name: 'sortByName'})export class SortByNamePipe {
    transform(value, [queryString]) {
        // console.log(value, queryString);
        return value.filter((student) => new RegExp(queryString).test(student.name))
        // return value;
    }}



达令说
浏览 829回答 3
3回答

杨魅力

为了完全理解问题和可能的解决方案,我们需要讨论角度变化检测 - 用于管道和组件。管道变化检测无状态/纯管默认情况下,管道是无状态/纯粹的。无状态/纯管道只是将输入数据转换为输出数据。他们不记得任何东西,所以他们没有任何属性 - 只是一种transform()方法。因此,Angular可以优化无状态/纯管道的处理:如果它们的输入没有改变,则在变化检测循环期间不需要执行管道。对于管道,如{{power | exponentialStrength: factor}},power和factor输入。对于这个问题,"#student of students | sortByName:queryElem.value",students和queryElem.value为输入,并且管sortByName是无状态/纯的。&nbsp;students是一个数组(引用)。添加学生时,数组引用不会更改 -&nbsp;students不会更改 - 因此不会执行无状态/纯管道。当在过滤器输入中输入某些内容时,queryElem.value确实会更改,因此会执行无状态/纯管道。解决阵列问题的一种方法是每次添加学生时更改数组引用 - 即,每次添加学生时创建新数组。我们可以这样做concat():this.students&nbsp;=&nbsp;this.students.concat([{name:&nbsp;studentName}]);虽然这很有效,但我们的addNewStudent()方法不应该仅仅因为我们使用管道而以某种方式实现。我们想用来push()添加到我们的数组中。有状态的管道有状态管道具有状态 - 它们通常具有属性,而不仅仅是transform()方法。即使输入没有改变,也可能需要对它们进行评估。当我们指定管道是有状态/非纯的时 -&nbsp;pure: false- 每当Angular的更改检测系统检查组件的更改并且该组件使用有状态管道时,它将检查管道的输出,无论其输入是否已更改。这听起来像我们想要的,即使它效率较低,因为我们希望管道执行即使students引用没有改变。如果我们只是使管道有状态,我们会收到一个错误:EXCEPTION:&nbsp;Expression&nbsp;'students&nbsp;|&nbsp;sortByName:queryElem.value&nbsp;&nbsp;in&nbsp;HelloWorld@7:6'&nbsp;has&nbsp;changed&nbsp;after&nbsp;it&nbsp;was&nbsp;checked.&nbsp;Previous&nbsp;value:&nbsp;'[object&nbsp;Object],[object&nbsp;Object]'.&nbsp;Current&nbsp;value:&nbsp;'[object&nbsp;Object],[object&nbsp;Object]'&nbsp;in&nbsp;[students&nbsp;|&nbsp;sortByName:queryElem.value根据@ drewmoore的回答,“此错误仅在开发模式下发生(默认情况下从beta-0开始)。如果enableProdMode()在引导应用程序时调用,则不会抛出错误。”&nbsp;国家文件ApplicationRef.tick():在开发模式中,tick()还执行第二个更改检测周期,以确保不会检测到进一步的更改。如果在第二个周期中拾取了其他更改,则应用中的绑定会产生无法在单个更改检测过程中解决的副作用。在这种情况下,Angular会抛出一个错误,因为Angular应用程序只能有一个更改检测通道,在此期间必须完成所有更改检测。在我们的场景中,我认为错误是虚假/误导。我们有一个有状态的管道,每次调用时输出都会改变 - 它可能有副作用,这没关系。NgFor在管道之后进行评估,因此它应该可以正常工作。但是,我们无法真正开发此错误,因此一种解决方法是将数组属性(即状态)添加到管道实现并始终返回该数组。请参阅@ pixelbits对此解决方案的回答。但是,我们可以更高效,并且正如我们将看到的,我们将不需要管道实现中的数组属性,并且我们不需要针对双重更改检测的变通方法。组件变化检测默认情况下,在每个浏览器事件中,角度变化检测都会遍历每个组件以查看它是否发生了变化 - 输入和模板(以及其他东西?)都会被检查。如果我们知道组件仅依赖于其输入属性(和模板事件),并且输入属性是不可变的,那么我们可以使用更有效的onPush变更检测策略。使用此策略,不会检查每个浏览器事件,只有在输入更改和模板事件触发时才会检查组件。而且,显然,我们没有Expression ... has changed after it was checked通过此设置获得该错误。这是因为在onPush再次“标记”(ChangeDetectorRef.markForCheck())之前不会再次检查组件。因此,模板绑定和有状态管道输出仅执行/评估一次。除非输入改变,否则无状态/纯管道仍未执行。所以我们仍然需要一个有状态的管道。这是@EricMartinez建议的解决方案:带有onPush变化检测的有状态管道。请参阅@ caffinatedmonkey对此解决方案的回答。请注意,使用此解决方案时,该transform()方法不需要每次都返回相同的数组。我发现有点奇怪:没有状态的有状态管道。再考虑一下......有状态管道可能应该总是返回相同的数组。否则,它只能与onPush开发模式下的组件一起使用。毕竟,我认为我喜欢@ Eric和@ pixelbits的答案的组合:有状态管道返回相同的数组引用,onPush如果组件允许则进行更改检测。由于有状态管道返回相同的数组引用,因此管道仍可用于未配置的组件onPush。Plunker这可能会成为Angular 2的习惯用法:如果数组正在输入管道,并且数组可能会更改(数组中的项目,而不是数组引用),我们需要使用有状态管道。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

AngularJS