Изменение порядка массива в Aurelia, странное поведение

#javascript #aurelia

#javascript #aurelia

Вопрос:

Я пытаюсь создать пользовательский элемент для управления простыми списками, переименования элементов и изменения их порядка. К сожалению, я замечаю какое-то странное поведение, которое на самом деле очень сложно определить.

  1. Ввод входных данных, по-видимому, не распознается как изменения для Aurelia для обновления элемента
  2. При вводе / изменении одного элемента после загрузки страницы, а затем изменении его положения в массиве с помощью этих методов индекс элемента кажется потерянным (превращается в -1). Если элемент не изменен через поле ввода, индекс в массиве распознается правильно, и сортировка работает.

Есть ли какие-либо известные проблемы с массивами, привязкой и, возможно, даже дочерними элементами? Какие методы тестирования используются для получения желаемого поведения? Большое спасибо!

Родительский элемент

 ...   
<list items.bind="list"></list>
...   
  

Элемент списка

 <template>
<div class="input-group" repeat.for="item of items">
     <input value.bind="item" class="input"  type="text" placeholder="Item" autofocus>
     <a click.delegate="deleteItem(item)">X</a>
     <a click.delegate="moveItemUp(item)">^</a>
     <a click.delegate="moveItemDown(item)">v</a>
</div>
<a click.delegate="addItem()">Add Item</a>
  

Список JS

  export class List {

  @bindable({defaultBindingMode: bindingMode.twoWay}) items;

  constructor() {}

  addItem() {
    this.items.push('new')
  }

  deleteItem(item) {
    let i = this.items.indexOf(item)
    this.items.splice(i, 1)
  }

  moveItemUp(item) {
    let i = this.items.indexOf(item)
    if (i === 0) return
    let temp = item
    this.items.splice(i, 1)
    this.items.splice(i - 1, 0, temp)
  }

  moveItemDown(item) {
    let i = this.items.indexOf(item)
    if (i === this.items.length) return
    let temp = item
    this.items.splice(i, 1)
    this.items.splice(i, 0, temp)
  }

}
  

Ответ №1:

repeat.for имеет несколько контекстных переменных, которые вы можете использовать. [Документация]

Демонстрация сути: https://gist.run/?id=1c8f78d8a774cc859c9ee2b1ee2c97f3

  • Правильная позиция текущего элемента может быть определена с помощью $index контекстной переменной вместо items.indexOf(item) .
  • Значения входных данных будут сохранены путем передачи item в items.slice(newIndex, item) .

Если вам нужно наблюдать за изменениями массива, CollectionObserver может отлично подойти для этого. Подробнее здесь: Наблюдение за объектами и массивами в Aurelia.

list.js

 import { bindable, bindingMode } from 'aurelia-framework';

export class List {

  @bindable({defaultBindingMode: bindingMode.twoWay}) items;

  constructor() {} 

  addItem() {
    this.items.push(`New Item ${this.items.length   1}`);
  }

  deleteItem(i) {
    this.items.splice(i, 1);
  }

  moveItemUp(i, item) {
    if (i === 0) 
      return;

    this.moveItem(i, i - 1, item);
  }

  moveItemDown(i, item) {
    if (i === this.items.length - 1) 
      return;

    this.moveItem(i, i   1, item);
  }

  moveItem(oldIndex, newIndex, item) {
      this.items.splice(oldIndex, 1);
      this.items.splice(newIndex, 0, item);
  }

}
  

list.html

 <template>
    <div class="input-group" repeat.for="item of items">
         <input value.bind="item" class="input"  type="text" placeholder="Item" autofocus> | 
         <a click.delegate="deleteItem($index)"><i class="fa fa-close"></i></a> | 
         <a click.delegate="moveItemUp($index, item)"><i class="fa fa-arrow-up"></i></a> | 
         <a click.delegate="moveItemDown($index, item)"><i class="fa fa-arrow-down"></i></a>
    </div>
    <a click.delegate="addItem()">Add Item</a>
</template>
  

Ответ №2:

Я считаю, что это связано с неизменностью строк. То есть строки не могут быть изменены, поэтому при изменении значения в текстовом поле элемент массива фактически заменяется, а не изменяется. Вот почему вы теряете привязку.

Вот суть, которая демонстрирует правильную работу при привязке к списку объектов.

https://gist.run/?id=22d186d866ac08bd4a198131cc5b4913