0
<ul class="todo-list">
      <li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone, editing: todo.editing}" >
        <div class="view">
          <input class="toggle"
            type="checkbox"
            [checked]="todo.isDone"
            (click)="toggleTodo(todo)">
          <label (dblclick)="todo.editing = true">{{todo.title}}</label>
          <button class="destroy" (click)="destroyTodo(todo)"></button>
        </div>
        <input class="edit"
               #updatedTodo
               [value]="todo.title"
               (blur)="updateTodo(todo, updatedTodo.value)"
               (keyup.escape)="todo.editing = false"
               (keyup.enter)="updateTodo(todo, updatedTodo.value)">
      </li>

</ul>

https://github.com/amejiarosario/angular-todo-app/blob/master/src/app/todo/todo.component.html

I modified the code from this repository and one thing I noticed is that the editing property is not found in the original todos array objects, and is being created inside the html component or maybe elsewhere, I am thinking it's being instantiated in the event listeners, but is it a good idea to do that? I had trouble with it, so I had to instantiate it inside the todos.

Also, instantiating it here in the event listeners means we can't modify the property editing inside the service component, right?

2
  • Please include the code needed to understand the question, in the question, not just on an external site. Commented Mar 27, 2020 at 15:16
  • If you can access an object from the component (ts) code you can modify its properties. A property that isn't set (instantiated) is just undefined. In TypeScript objects need to have the type any for you to access any property without errors, e.g let TODOS: any[] = [ ] Commented Mar 27, 2020 at 15:48

2 Answers 2

1

It is set in the event listeners, yes. Here:

<label (dblclick)="todo.editing = true">

And here:

(keyup.escape)="todo.editing = false"

Of course, if it is not initialized anywhere else, then it will be initialized here. But regardless, it's a terrible idea to mutate objects in such a way from Angular point of view. It would not work with OnPush change detection strategy for example. Principle of immutability is important for Angular because if you manage change detection correctly, it will only do checks by references and mutated changes won't necessarily show up. What those events should really do is trigger functions that update that specific object by reconstructing it and then replace it in the array by reconstructing the array as well. E.g.

setIsEditing(todoToUpdate: Todo, editing: boolean): void {
  this.todos = this.todos.map(todo => todo === todoToUpdate ? {...todoToUpdate, editing} : todo);
}

Of course in this way changes to todos will destroy and recreate todo DOM elements by *ngFor (which is intended). But you can also improve that by using a trackBy function. Something like component.ts

trackById(index, todo: Todo): string {
  return todo.id;
}

component.html

 <li *ngFor="let todo of todos; trackBy: trackById" [class.completed]="todo.isDone" [class.editing]="todo.editing" >

You don't always have to do this, but I just wanted to show you an example. The reason you would do this is to achieve great performance in real world app. But your app seems more like a learning app, thus does things in the simplest way possible, I think that's also why properties are added in the event handlers.

Sign up to request clarification or add additional context in comments.

Comments

0

HTML attributes only consist of text, not parentheses ((/)), brackets ([/]), or curlies ({/}). I think that's why your code was not working, it isn't an Angular problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.