模型更改时,Aurelia repeat.for不会刷新 [英] Aurelia repeat.for does not refresh when model changes

查看:81
本文介绍了模型更改时,Aurelia repeat.for不会刷新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用Aurelia构建一个简单的自定义组件,该组件允许用户输入一个或多个字符串.如果有多个项目,则列表中的每个项目均应显示删除按钮.

I want to build a simple custom component with Aurelia that allows user to input one or more strings. When there are more than one items, list should show remove button for each item on the list.

我的问题是,当列表中有多个项目时,列表的第一项没有显示删除按钮. 外观是

My problem is that the first item of the list does not show remove button when there are multiple items in the list. This is how it looks

这是我用于自定义列表组件的代码和html:

Here is the code and html I have for the custom list component:

查看

<template>
  <div repeat.for="item of items">
    <input type="text" value.bind="items[$index]">
    <button click.delegate="remove($index)" 
            if.bind="hasMoreThanOne()">Remove</button>
  </div>
  <button click.delegate="add()">Add</button>
</template>

ViewModel

export class List {
  items: string[];

  constructor() {
    this.items = [];
    this.add();
  }

  add() {
    this.items.push("");
  }

  hasMoreThanOne() {
    return this.items.length > 1;
  }

  remove(index) {
    this.items.splice(index,1);
  }
}

我的问题有两个:

  • 为什么列表长度更改时第一个列表项没有自动更新?
  • 如何使第一个项目也显示删除"按钮?

推荐答案

Aurelia将bind命令中的任何函数视为纯函数.这意味着在传递给函数的参数更改之前,它将不会再次调用该函数.由于hasMoreThanOne()的返回值会根据不是该函数参数的值而改变(自然,因为该函数没有任何参数),所以Aurelia不会再次调用该函数.

Aurelia treats any functions that are part of a bind command as pure functions. This means that it will not call the function again until the parameters being passed to the function have changed. Since hasMoreThanOne() has a return value that changes based on something that isn't a parameter to the function (naturally, since the function doesn't have any parameters), Aurelia isn't going to call the function again.

数组更改时Aurelia不重新评估功能的原因是优化了转发器,并且看到数组中的第一项没有更改,因此它只是继续使用现有的DOM.使用正确创建的视图,可以极大地提高性能,但是对于您而言,这会导致不必要的问题.

The reason Aurelia doesn't re-evaluate the function when the array changes is that the repeater is optimized and sees that the first item in the array has not changed, so it just keeps using the existing DOM it has for it. With a properly created view, this helps greatly increase performance, but in your case, it's causing unwanted issues.

您发现了一种使用吸气剂的非最佳方式来解决此问题.这不是最佳选择的原因是,默认情况下,Aurelia每200毫秒使用一次脏检查来检查吸气剂的变化.这样可以解决您遇到的问题,但是对于性能而言并不是理想的选择.

You found one, non-optimal way to deal with this, by using a getter. The reason this is non-optimal is that Aurelia, by default, uses dirty checking every 200ms to check for changes to getters. This fixes the problem you had, but isn't ideal for performance.

考虑到hasMoreThanOne()函数的简单程度,最简单的选择是在绑定中简单地内联函数,如下所示:

The simplest option, given how simple the hasMoreThanOne() function is, would be to simply inline the function in your binding, like this:

<template>
  <div repeat.for="item of items">
    <input type="text" value.bind="items[$index]">
    <button click.delegate="remove($index)" 
            if.bind="items.length > 1">Remove</button>
  </div>
  <button click.delegate="add()">Add</button>
</template>

说实话,这就是我可能会处理的方式.

This is honestly how I would probably handle this.

您也可以在使用过程中使用吸气剂,但是将computedFrom装饰器附加到它上以防止脏检查:

You could also use the getter as you are doing, but attach the computedFrom decorator to it to preclude dirty checking:

import {computedFrom} from 'aurelia-framework';

export class List {
  items: string[];

  constructor() {
    this.items = [];
    this.add();
  }

  add() {
    this.items.push("");
  }

  @computedFrom('items.length')
  get hasMoreThanOne() {
    return this.items.length > 1;
  }

  remove(index) {
    this.items.splice(index,1);
  }
}

这将为您提供与我上面使用的内联绑定完全相同的性能,但是还有更多代码要编写.

This will give you the exact same performance as the inlined binding I used above, but there is a bit more code to write.

这篇关于模型更改时,Aurelia repeat.for不会刷新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆