简体   繁体   中英

Updating an observable collection from a parent component in Aurelia

To better understand interactions between Aurelia components, I've separated the list component of the Todo List app in Aurelia's quick start documentation into its own class and corresponding view. But doing so leads to the view not updating when a new element is added to the list.

My modified code is as follows:

app.html:

<template>
  <require from="./todo-list"></require>
  <h1>Todo list</h1>
  <form submit.trigger="addTodo()">
    <input type="text" value.bind="todoDescription">
    <button type="submit" disabled.bind="!todoDescription">Add Todo</button>
  </form>
  <todo-list></todo-list>
</template>

app.ts:

import { TodoList } from "todo-list";
export class App {
  todoList: TodoList = new TodoList();
  todoDescription = '';

  addTodo() {
    if (this.todoDescription) {
      this.todoList.addOne(this.todoDescription);
      this.todoDescription = '';
    }
  }
}

todo-list.html

<template>
  <ul>
    <li repeat.for="todo of todos">
      <input type="checkbox" checked.bind="todo.done">
      <span css="text-decoration: ${todo.done ? 'line-through' : 'none'}">
        ${todo.description}
      </span>
    </li>
  </ul>  
</template>

todo-list.ts:

export interface Todo {
  description: string;
  done: boolean;
}

export class TodoList {
  todos: Todo[] = [
    { description: "Make bed", done: true },
    { description: "Take out trash", done: false }
  ];

  addOne(todoDescription: string) {
    this.todos.push({
      description: todoDescription,
      done: false
    });
  }
}

The original, working code is as follows:

app.ts:

export interface Todo {
  description: string;
  done: boolean;
}

export class App {
  todos: Todo[] = [
    {description: "Make bed", done: true}, 
    {description: "Take out trash", done: false}
  ];
  todoDescription = '';

  addTodo() {
    if (this.todoDescription) {
      this.todos.push({
        description: this.todoDescription,
        done: false
      });
      this.todoDescription = '';
    }
  }
}

app.html:

<template>
  <h1>Todo list</h1>

  <form submit.trigger="addTodo()">
    <input type="text" value.bind="todoDescription">
    <button type="submit" disabled.bind="!todoDescription">Add Todo</button>
  </form>

  <ul>
    <li repeat.for="todo of todos">
      <input type="checkbox" checked.bind="todo.done">
      <span css="text-decoration: ${todo.done ? 'line-through' : 'none'}">
        ${todo.description}
      </span>
      <button click.trigger="removeTodo(todo)">Remove</button>
    </li>
  </ul>
</template>

Debugging shows that after the classes are separated, the todos array is indeed updated, but the view is not.

How can I modify my existing code so that when a new element is added to the todo list, the view is updated accordingly?

Aurelia creates an instance of TodoList when it sees the element. You have created a separate instance when you "newed" it up. Instead of creating a new instance of the TodoList class, you should use view-model.ref to capture a reference to the instance aurelia has created.

app.html

<template>
  <require from="./todo-list"></require>
  <h1>Todo list</h1>
  <form submit.trigger="addTodo()">
    <input type="text" value.bind="todoDescription">
    <button type="submit" disabled.bind="!todoDescription">Add Todo</button>
  </form>
  <todo-list view-model.ref="todoList"></todo-list>
</template>

app.ts

import { TodoList } from "todo-list";
export class App {
  todoList: TodoList;
  todoDescription = '';

  addTodo() {
    if (this.todoDescription) {
      this.todoList.addOne(this.todoDescription);
      this.todoDescription = '';
    }
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM