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.
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?
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
I'm trying to add a Bootstrap tab panel goes like this:
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" href="#tabs-1" role="tab">First Panel</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tabs-2" role="tab">Second Panel</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" href="#tabs-3" role="tab">Third Panel</a>
</li>
</ul><!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="tabs-1" role="tabpanel">
<p>First Panel</p>
</div>
<div class="tab-pane" id="tabs-2" role="tabpanel">
<p>Second Panel</p>
</div>
<div class="tab-pane" id="tabs-3" role="tabpanel">
<p>Third Panel</p>
</div>
</div>
Now I need to give link to users to see the panes like this:
https://sitename.com/page#tabs-2
But this won't work because the tab-pane with an id of tabs-2 does not have the .active class.
However, if I try loading https://sitename.com/page#tabs-1 The page properly redirects me to tab-pane with an id of tabs-1 (because it has .active class by default)
So how can I redirect users to different tab panes correctly?
You don't really need to check the fragment to switch between those tabs.
1) Import jQuery from here or:
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
2) Add this part to your code.
<script>
$(document).ready(function () {
$('.nav-tabs a').click(function () {
$(this).tab('show');
});
});
</script>
I already started answering your old question before you deleted it, but here is it again.
I didn't understood what you were trying to achieve, so I just looked into the code and made my version, its not the best but it works.
This is an onClick event handler, it gets executed on a click in your nav and changes the active classes.
// onClick event handler, gets executed on click
$(".nav-link").on("click", (e) => {
// store clicked element
const listItem = e.target;
// get hash
const hash = e.target.hash;
// remove all active classes
$(".nav-link, .tab-pane").removeClass("active");
// add active class to list item and tab panes
$(listItem).add(hash).addClass("active");
});
This part gets executed when you reload your page. You need to change your HTML for this to work, so remove the active class from nav-link and give every link an additional class (tabs-1, tabs-2 and tabs-3).
// when page is reloaded
$(document).ready(() => {
// get current hash
const hashList = window.location.hash;
const hashItems = hashList.slice(1);
// remove all active classes
$(".nav-link, .tab-pane").removeClass("active");
// add active class to nav-link and pane
$(hashList).add(`.${hashItems}`).addClass("active");
});
Both snippets need to be included in your script tag of course, also you need to import jQuery, if not already happened.
I have a service page that using bootstrap 4's pills .nav-pills navigation (this is not the main navigation navbar), which is working very well. My challenge is that i want to be able to click on a link on the home page that should open the targeted tab-panel on the service page. Haven't been able to find a way for almost a week now. How can i achieve this?
Service.html
<div class="nav flex-column nav-pills col-md-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<ul class="list-group list-unstyled">
<li class="nav-item">
<a class="nav-link list-group-item" id="v-pills-manpower-tab" data-toggle="pill" href="#v-pills-manpower" role="tab" aria-controls="v-pills-manpower" aria-selected="false">Manpower Supply</a>
</li>
</ul>
</div>
<div class="tab-content col-md-8" id="v-pills-tabContent">
<div class="tab-pane fade" id="v-pills-manpower" role="tabpanel" aria-labelledby="v-pills-manpower-tab">
<h5>Man Power Supply</h5>
</div>
Home.html
<a href="services.html#v-pills-manpower" data-toggle="tab" >
My code in home.html doesn't work but that's one of my many attempts.
On the home page, configure data attributes to help. I've added data-tab-name to the anchor and it defines the desired, selected tab for the service page.
When the page loads, it re-configures the onclick of the link so that the tab name can be stored in localStorage before redirecting the user to the service page.
Home.html
<a href="services.html" data-tab-name="v-pills-manpower" data-toggle="tab" >
<script type="text/javascript">
window.onload = function() {
document.querySelectorAll('[data-toggle="tab"]').forEach(function(item, index){
item.addEventListener('click', function(e){
e.preventDefault();
localStorage.selectedTabName = item.getAttribute('data-tab-name');
window.location.href = item.href;
});
});
};
</script>
When the service page loads, the javascript looks for the saved tab name in localStorage, identifies that tab and then makes it the active tab by applying the "active" class to the appropriate element.
Service.html
<script type="text/javascript">
window.onload = function() {
document.querySelectorAll('.nav-link').forEach(function(item, index){
var isActive = (item.className.indexOf('active')>-1);
if (item.id==localStorage.selectedTabName) {
if (!isActive) {
item.className += ' active';
}
item.setAttribute('aria-selected', 'true');
} else {
item.setAttribute('aria-selected', 'false');
if (isActive) {
item.className = item.className.replace('active', '');
}
}
});
};
</script>
I am using ui-router within my AngularJS app. I have two states, one of which is a child.
.state('patents', {
url: '/patents',
component: 'patents'
})
.state('patents.patent', {
url: '/{patentId}',
component: 'patent'
})
In the parent state (patents), I have a table with a column with dynamic buttons, some which direct users to separate states, but one needs to direct the user to tab content, which is third in the ul within the child state patents.patent.
//Child state
<div class="view-tabs">
<ul class="nav view-pills">
<li ng-click="activeSelectedTab = 0; $ctrl.activePatentItemMenu = 'Patent Info'" ng-class="{active : $ctrl.activePatentItemMenu === 'Patent Info'}">Patent Info</li>
<li ng-click="activeSelectedTab = 1; $ctrl.activePatentItemMenu = 'Cost Analysis'" ng-class="{active : $ctrl.activePatentItemMenu === 'Cost Analysis'}">Cost Analysis</li>
<li ng-click="activeSelectedTab = 2; $ctrl.activePatentItemMenu = 'Renewal History'" ng-class="{active : $ctrl.activePatentItemMenu === 'Renewal History'}">Renewal History</li>
</ul>
</div>
<uib-tabset type="pills" active="activeSelectedTab">
//ALL TAB CONTENT WHICH IS DISPLAY APPROPRIATELY
</uib-tabset>
In the controller, activePatentItemMenu is set to Patent Info, so the first li item and its content is the first thing anyone sees, which is the default. I need the active class to be set to the 3rd li item Renewal History only if the user clicks on the specified button in the table, labeled renewal history.
Question
How do I set an active state to the third li item in the child state, only when a specific button is clicked in the parent state?
You should consider using ui-sref and ui-sref-active
<ul class="nav view-pills">
<li ui-sref-active="active">
<a ui-sref="patents.patent({patentId: 'Patent Info'})">Patent Info</a>
</li>
...
</ul>
Then use state.params in your controller to find the active uib-tabset
In my application i have to implement hide and show side menu. By default the page menu is open while clicking the toggle menu i have to hide the side menu. How can i implement this.
what i have is:
app.component.html, nav.component.html
<div class="menu-toggler sidebar-toggler">
<span></span>
</div>
<ul>
<li class="nav-item ">
<a class="nav-link nav-toggle">
<i class="icon-diamond"></i>
<span class="title">Name</span>
<span class="arrow"></span>
</a>
</li>
</ul>
Myservice.ts
export class GlobalService {
public collapse;
constructor() { }
setValue(val: boolean) {
this.collapse = val;
}
getValue() {
return this.collapse;
}
EDIT
app.component.html
<div *ngIf="!toggle()"class="menu-toggler sidebar-toggler">
<span></span>
</div>
app.component.ts
import { GlobalService } from "path";
export class AppComponent {
toggle() {
this.globalService.setValue(false);
}
}
how can i hide this list(in nav.html) while clicking menu toggle (app.compnent.html)? Any help will really appreciable. i am new to angular.
If use of service is not the priority then you can simply maintain simple variable to do this task.
Your app.component.ts
export class AppComponent {
showMenu : boolean = true;
}
Your app.component.html
<div (click)="showMenu = !showMenu" class="menu-toggler sidebar-toggler"><span></span>
</div>
<ul *ngIf="showMenu">
<!-- used showMenu to hide/show -->
<li class="nav-item ">
<a class="nav-link nav-toggle">
<i class="icon-diamond"></i>
<span class="title">Name</span>
<span class="arrow"></span>
</a>
</li>
</ul>
hope this helps ...
For this ,
You can make a CommonService to store the state of menu or and use that Service to make toggle you menu.
You can also use #Input #Output , in case you are having parent child relation between components.
Method will depend on how is your project/file structure.
You can create a service and preferably make a static variable inside to get and set the visibility state of the menu. By this you could directly set and get the variable by using ComponentName.variableName.
to play with the visibility you could use(Sorry if there is any syntax errors)
1> Set the document.getelementbyid("idofelement").display= none or block
2>use *ngIf="someboolean" where you should set the boolean in your ts file
In my Meteor app I need to add class to navigation item when page is active.
How can I do that?
Template.header.helpers({
getActiveClass: function(routeName) {
var active = Router.current() && Router.current().route.getName() === routeName;
return active && 'active';
}
});
<li class="{{getActiveClass 'home'}}">
Home
</li>
Note if you want to make the element active for more than one route you have to modify the getActiveClass helper a little bit.
Add Package zimme:iron-router-active
Use as follows:
class="{{isActiveRoute regex='<route>'}}"
For example
<li class="{{isActiveRoute regex='dashboard'}}">
<a href="{{pathFor route='dashboard'}}"><i class="fa fa-th-large"></i> <span
class="nav-label">Dashboard</span> </a>
</li>
So whenever the Route is active, Link will be Active.