M Usama Alvi
M Usama Alvi

Reputation: 207

Change HTML in Angular 7 by reference

I'm passing UL by reference in an Angular function and I want to append some 'li' in that UL.

  <ng-container *ngIf="FileUploaded">
              <tr class="" *ngFor="let row of this.fileJson">
                <td class="text-left">{{row.Comment}}</td>
                <td class="text-center">

                  <div class="tags">
                    <ul class="tags tags--ds ui-sortable" #forAddingTag> // This is the reference which is passed in below button's function named "AddTag()"
                      <ng-container *ngFor="let key of this.Object.keys(row)">
                        <li #ToRemoveTag class="tags__item" *ngIf="key.substring(0,5)=='Topic'">
                          <p>{{row[key]}}</p> <span class="close__item"><i class="fal fa-times"
                              (click)="removeTag(ToRemoveTag)"></i></span>
                        </li>
                      </ng-container>

                    </ul>
                  </div>

                </td>
                <td class="text-center">
                  <a class="btn" (mousedown)="AddTag(forAddingTag)">Update</a> // Here the reference is being passed
                </td>

              </tr>

            </ng-container>

Here is the typescript code

AddTag(evalue){
    debugger

      var text = "";
      if (window.getSelection) {
          text = window.getSelection().toString();
      } 
      var value = text;

  }

I just want to add some more "li" at the end of this UL. I can do it with the help of JQuery but it shouldn't be used in Angular.

Upvotes: 0

Views: 141

Answers (1)

Barremian
Barremian

Reputation: 31125

I'd recommend not to run any function in the *ngFor tag. It'll be called too many times than you think it does. Better way would be to create another object in the controller (something like filteredRows) and loop over it in the template with the keyvalue pipe.

Template

<ng-container *ngIf="FileUploaded">
  <tr class="" *ngFor="let row of filteredRows; let rowIndex=index">
    <td class="text-left">{{ row.comment }}</td>
    <td class="text-center">
      <div class="tags">
        <ul class="tags tags--ds ui-sortable" #forAddingTag>
          <ng-container *ngFor="let topic of filteredRows.topics | keyvalue; let topicIndex=index">
            <li #ToRemoveTag class="tags__item">
              <p>{{ topic.value }}</p> <span class="close__item"><i class="fal fa-times"(click)="removeTag(rowIndex, topicIndex)"></i></span>
            </li>
          </ng-container>
        </ul>
      </div>
    </td>

    <td class="text-center">
      <a class="btn" (mousedown)="addTag(rowIndex)">Update</a>
    </td>
  </tr>
</ng-container>

Then you could modify the filteredRows variable (add/remove properties) to reflect the changes in the template.

Controller

filteredRows: {comment: any, topics: any[]}[];

ngOnInit() {
  fileJson.forEach(row => {
    const comment = row['Comment'];
    const topics = JSON.parse(JSON.stringify(row));    // <-- create a deep copy of `row` object
    for (const key in topics) {
      if (topics.hasOwnProperty(key)) {
        if (key.substring(0, 5) !== 'Topic') {
          delete topics[key];
        }
      }
    }
    this.filteredRows.push({comment: comment, topics: topics});
  });
}

addTag(index) {
  this.filteredRows[index].topics.push(
    {
      // object content
    }
  );
}

removeTag(rowIndex, topicIndex) {
  delete this.filteredRows[rowIndex].topics[topicIndex];
}

Function name AddTag() goes against the usual convention of camel case naming for functions.

Upvotes: 1

Related Questions