Angular - how to use one function to manage multiple toggles / click events?

Viewed 457

Please see attached image.

So, this is a navbar, where clicking on any of the tabs, the content below the nav will change based on which tab is selected.

enter image description here

Here is code for an example of how the function works for when click event is handled when Bespoke Manufacturing is clicked:

 toggleBespoke() {
   this.showBespoke = true;
   this.showHow = false;
   this.showCasting = false;
   this.showForging = false;
   this.showInjection = false;
   this.showPressing = false;
   this.showTurning = false;
 }

As you can see, it's simple, the about showAbout variable is set to true whilst all the others are manually set to false.

ngClass is used which gives the blue highlighted effect so only one of the tabs gets highlighted when selected as only one can be true whilst others are false.

The same logic is then applied to the 6 other tabs.

But this is my question, what is the way to prevent code duplication and handle such click events in one function only?

4 Answers

You can use a property in your component which stores the active tab.

export class AlarmsComponent {
  activeTab = 'bespoke';
}

And then you can use it in your template like this:

<ul class="tabs">
  <li>
    <a (click)="activeTab = 'bespoke'"
       [ngClass]="{active: activeTab === 'bespoke'}"
    >
      Bespoke manufacturing
    </a>
  </li>
  <li>
    <a (click)="activeTab = 'how'"
       [ngClass]="{active: activeTab === 'how'}"
    >
      How it works
    </a>
  </li>
</ul>

<div class="tab-bespoke" *ngIf="activeTab === 'bespoke'">
  Bespoke manufacturing tab content
</div>
<div class="tab-how" *ngIf="activeTab === 'how'">
  How it works tab content
</div>

Another solution (dirtier than the previous one) is to create a single function executed on click passing the $event param.

For instance you have something like the following to manage the nav item:

<li class="nav-item"><a id="bespoke" class="nav-link" href="#" tabindex="-1" (click)="onClick($event)">BESPOKE MANUFACTURING</a> </li>

And inside the class you have onClick function as the following:

onClick(ev){
 let clickedId = ev.target.id;
 //clickedId is the id of the clicked element and you can add class accordingly
 if(clickedId === 'bespoke'){
  //the user clicked the bespoke item 
 }
}

Create a variable to store the current active tab, in interaction with tab set current clicked tab to activeTab, then apply active inactive class using this variable ,for example in

app.component.ts

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  activeTab: string = 'tab1';

  isActive(tabName){
    return this.activeTab === tabName;
  }

  makeActive(tab){
    this.activeTab = tab;
  }
}

in Html

app.component.html

<ul class="nav nav-tabs">
  <li class="nav-item">
    <a [ngClass]="{'nav-link': true, 'active':isActive('tab1')}" (click)="makeActive('tab1')">Tab 1</a>
  </li>
  <li class="nav-item">
    <a [ngClass]="{'nav-link': true, 'active':isActive('tab2')}" (click)="makeActive('tab2')">Tab 2</a>
  </li>
  <li class="nav-item">
    <a [ngClass]="{'nav-link': true, 'active':isActive('tab3')}"  (click)="makeActive('tab3')">Tab 3</a>
  </li>
  <li class="nav-item">
    <a [ngClass]="{'nav-link': true, 'active':isActive('tab4')}"  (click)="makeActive('tab4')">Tab 4</a>
  </li>
</ul>

<div>
  <div class="tab-bespoke" *ngIf="isActive('tab1')">
     tab 1 content
  </div>
   <div class="tab-bespoke" *ngIf="isActive('tab2')">
     tab 2 content
  </div>
   <div class="tab-bespoke" *ngIf="isActive('tab3')">
     tab 3 content
  </div>
   <div class="tab-bespoke" *ngIf="isActive('tab4')">
     tab 4 content
  </div>

</div>

here is the running sample https://stackblitz.com/edit/angular-bootstrap-4-starter-cbrzm5

I'd go with the framework and actually use proper routing instead of hiding content by hand.

as a bonus, you'll get the current tab get set to automatically when the user refresh the page.

Related