0

I have the following block of template code in Angular 9, with a condition to show either a view (eye) icon or an edit (pencil) icon. As you can see, much of the HTML is identical, with only a few attributes and the click binding that are different.

<button *ngIf="!(hasEditAccess$ | async)" type="button" class="icon-button" (click)="entityViewClicked()" aria-label="View">
    <i class="far fa-eye" aria-hidden="true" title="View"></i>
</button>
<button *ngIf="hasEditAccess$ | async" type="button" class="icon-button" (click)="entityEditClicked()" aria-label="Edit">
    <i class="fas fa-pencil-alt" aria-hidden="true" title="Edit"></i>
</button>

Without creating a new component, is there a cleaner way to write this HTML and the conditional statement once, rather than repeating so much of it?

I'm thinking this may involve {{ interpolation }} syntax and some kind of template variable, but I welcome any approach that reduces the code duplication.

3
  • 2
    Ah, I had added an answer for using ng-container, but I had mis read your question. You have a lot of different properties that need to get changed so you would either have one button with conditionals on all the properties. or what you have now 2 separate buttons each in an ngIf. I think this way is probably easier to read. Commented Jul 22, 2020 at 18:59
  • If you subscribe to same thing multiple times in template I would also multicast the observable. aka. .pipe(share()); Commented Jul 22, 2020 at 19:21
  • @hyperdrive I've never used the share() operator before. I'll have to dig into it. Thanks! Commented Jul 22, 2020 at 20:26

1 Answer 1

1

You can avoid repeating the condition with *ngIf ... else:

<button *ngIf="hasEditAccess$ | async; else viewButton" type="button" class="icon-button" (click)="entityEditClicked()" aria-label="Edit">
    <i class="fas fa-pencil-alt" aria-hidden="true" title="Edit"></i>
</button>
<ng-template #viewButton>
  <button type="button" class="icon-button" (click)="entityViewClicked()" aria-label="View">
      <i class="far fa-eye" aria-hidden="true" title="View"></i>
  </button>
</ng-template>

Now if you want to use a single button declaration to handle both "view" and "edit" scenarios, you can associate a variable to the *ngIf condition and use that variable in conditional bindings. In the example below, the click event is a common method entityClicked with a parameter indicating if it is used in an editing context.

<button *ngIf="hasEditAccess$ | async as canEdit" type="button" class="icon-button" 
  (click)="entityClicked(canEdit)" 
  [attr.aria-label]="canEdit ? 'Edit' : 'View'">
  <i aria-hidden="true" 
    [ngClass]="canEdit ? 'fas fa-pencil-alt' : 'far fa-eye'" 
    [title]="canEdit ? 'Edit' : 'View'"></i>
</button>
Sign up to request clarification or add additional context in comments.

1 Comment

Excellent! I knew about else, but didn't think it helped much with the duplication issue. However, I didn't know the as keyword could be used within an *ngIf to create a new variable reference. Thanks!

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.