Search code examples
javascriptangularpopoverangular-bootstrapviewchild

ng-bootstrap Popover - How to add a link to a single word from a large string


I have an icon that displays an alert for each student. It contains some big string and I am required to add some links based on some variables.

Example of alert input: 'Alex was the best student in Math with 6.'.
Example of alert output: 'Alex' is clickable (but I need to use Angular Router in order to avoid reload page). 'Alex' is a variable that I get from 'item.item.alert'.
Example of an 'item.item.alert' string: 'ALEX|MATH|6' where the first element is the student name, the second element is the course and the third element is its grade. So I format this string using 'FormatAlert' function.

Summarizing, I need to make 'Alex' or whatever given student clickable. I tried to add an click event listener but I always get 'null' of 'undefined' when I printed '#coursesAlert' using @ViewChild and ngAfterViewInit().

...
<ng-template #courses let-item="value">
    <!-- Template of Popover --> 
    <ng-template #coursesAlert>
        <div [innerHTML]="FormatAlert(item.item.alert) | safeHtml"></div> <--- Alert output (to fix)
    </ng-template>
    <!-- Popover Configuration -->
    <div class="hidden-md-down">
        <span>{{item.item.id}}</span>
        <i *ngIf="item.item.alert" 
            class="fas fa-exclamation-circle text-danger ml-1 mr-1"
            #popoverAlert="ngbPopover"
            [ngbPopover]="coursesAlert"
            [closeDelay]="3000"
            [container]="'body'"
            triggers="mouseenter:mouseleave"
            placement="right">
        </i>
    </div>
</ng-template>

I just replicate the situation here (Objective is to handle just one word on a large text): https://stackblitz.com/edit/angular-mdqz9b-74ins9?embed=1&file=src/app/popover-tplcontent.html


Solution

  • What I understand is that you want to make the names clickable only. I refactored your formatGrades method to return name, and content separately.

    formatGrades: any[] = this.grades.split("|||").map(grade => {
        let name: string = grade.split("|")[0];
        let course: string = grade.split("|")[1];
        let gradeResult: string = grade.split("|")[2];
        
        var content = " got in " + course + " the grade of: " + gradeResult + '.';
        
        return {name : name, content: content};
    
      });
    
      onNameClick(e){
        console.log('onNameClick');
        console.log(e);
      }
    

    now in the UI can make the name a clickable button. you can style your button using css here too.

    <div *ngFor="let item of formatGrades">
      <i
        *ngIf="item"
        class="fas fa-exclamation-circle text-danger ml-1 mr-1"
        #popoverAlert="ngbPopover"
        [ngbPopover]="publicAlertContent"
        [closeDelay]="3000"
        [container]="'body'"
        triggers="mouseenter:mouseleave"
        placement="right"
      >
      </i>
      <br />
      <br />
      <ng-template #publicAlertContent>
        <div>
          <button (click)="onNameClick($event)">{{item.name}}</button>
          <span>{{item.content}}</span>
        </div>
      </ng-template>
    </div>
    

    enter image description here