简体   繁体   中英

Angular: Hiding/showing elements by ngIf or Toggling a class?

I'm wondering what the best way to approach this problem is and I'm very new to TypeScript and Angular. Using Angular 5.

Anyway. I have a list of elements on a page via a table.

在此处输入图片说明

This is the code that controls said list.

<tbody>
      <tr class="text-center" *ngFor="let topic of topics">
        <td *ngIf="!editTopicMode">{{ topic.name }}</td>
        <td id="{{topic.id}}" *ngIf="editTopicMode">
          <form>
            <div class="form-group">
              <input class="form-control" type="text" name="name" value="{{topic.name}}" />
            </div>
          </form>
        </td>
        <td>
          <div *ngIf="!editTopicMode" class="btn-group btn-group-sm">
            <button class="btn btn-link" (click)="editTopicBtnClick(topic.id)">
              <i class="fa fa-pencil fa-2x" aria-hidden="true"></i>
            </button>
            <button class="btn btn-link">
              <i class="fa fa-trash fa-2x" aria-hidden="true"></i>
            </button>
          </div>
          <div *ngIf="editTopicMode" class="btn-group-sm">
            <button class="ml-2 btn btn-sm btn-outline-secondary" (click)="cancelEditMode()">Cancel</button>
            <button class="ml-2 btn btn-sm btn-outline-primary">Save</button>
          </div>
        </td>
      </tr>
    </tbody>

What I'm aiming to do is that if a user clicks on the pencil(edit) icon, then the adjacent div changes from just a regular td to an input and the edit/delete buttons to change to a cancelEdit/save edits button group. (I know that I need to change the html a bit because the buttons aren't in the form element currently, but I'm not there on the wiring it up part).

I've thought of two ways to do this. 1) with ngIf's so that I can conserve the elements that are rendered and the edit/cancel buttons toggle the editMode; or 2) use ngClass and toggle display:none css classes for the button clicked.

Right now, when you click the edit button, regardless of which edit button you click, it flips all the columns to inputs, rather than just the row the user wants to edit.

在此处输入图片说明

Here's my component ts:

import { Component, OnInit, TemplateRef, ElementRef, ViewChild, Inject } from '@angular/core';
import { Topic } from '../models/topic';
import { TopicService } from '../services/topicService/topics.service';
import { AlertifyService } from '../services/alertify/alertify.service';
import { ActivatedRoute } from '@angular/router';
import { DOCUMENT } from '@angular/common'; 

@Component({
  selector: 'app-topics',
  templateUrl: './topics.component.html',
  styleUrls: ['./topics.component.css']
})

export class TopicComponent implements OnInit {
  @ViewChild('topicId') topicId: ElementRef;

  topics: Topic[];
  newTopic: Topic = {
    id: 0,
    name: '',
  };
  editTopicMode = false;

  constructor(
    @Inject(DOCUMENT) document,
    private topicsService: TopicService,
    private alertify: AlertifyService,
    private route: ActivatedRoute
  ) { }

  ngOnInit() {
    //this.route.data.subscribe(data => {
    //  this.topics = data['topics'];
    //})
    this.getTopics();
  }

  getTopics() {
    this.topicsService.getAllTopics()
      .subscribe(data => {
        this.topics = data;
      }, error => {
        this.alertify.error(error);
      });
  }

  addTopic() {
    this.topicsService.createTopic(this.newTopic)
      .subscribe((topic: Topic) => {
        this.topics.push(topic);
        this.alertify.success(this.newTopic.name + ' added as a new topic.');
        this.newTopic.name = '';
      },
      (err: any) => {
        this.alertify.error(err);
      }
    )
  }

  editTopicBtnClick(event) {
    console.log(event);
    this.editTopicMode = true;
    console.log(document.getElementById(event));
  }

  cancelEditMode() {
    this.editTopicMode = !this.editTopicMode;
  }

}

Any thoughts on the best (most efficient) way to make this happen?

Using *ngIf is fine just make sure that you set the *ngIf variable to point to somethign specific to the particular row of the *ngFor

this example could be cleaner but you could accomplish it as simply as

<button (click)="topic.edit = true" *ngIf="topic.edit === false">edit</button>
<button (click)="topic.edit = false" *ngIf="topic.edit === true">cancel</button>

You've done all the hard work already.

For single item editing, all that's left is: change editTopicMode to something like editTopicId .

Then you can:

  • Set it to topic.id on edit enabled, and null for example on edit closed
  • Change your *ngIf to editTopicId === topic.id (or !== as needed)

And that should be all.


If you want to enable multiple editing, just add a property called isInEditMode to each topic.

  • Your *ngIf check becomes topic.isInEditMode
  • No isInEditMode property at all is just like false , because undefined is a falsy value
  • Set topic.isInEditMode to true on editing enabled, false on editing closed

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