Meteor: Change the class of link on click - javascript

Template:
<template name="header">
<div class="blog-masthead">
<div class="container">
<nav class="blog-nav">
<a class="blog-nav-item {{active}}" href="{{pathFor 'homePage'}}">Home</a>
{{#if currentUser}}
<a class="blog-nav-item {{active}}" href="#">{{Meteor.userId}}</a>
{{else}}
<a class="blog-nav-item {{active}}" href="{{pathFor 'loginPage'}}">Login</a>
<a class="blog-nav-item {{active}}" href="{{pathFor 'signUpPage'}}">Sign Up</a>
{{/if}}
<a class="blog-nav-item {{active}}" href="#">About</a>
</nav>
</div>
</div>
</template>
header.js
Template.header.events({
'click a': function(e) {
e.preventDefault();
this.active?"active":"";
}
});
I just want to make set click link's class as active. Clicked link class should look like class="blog-nav-item active".

The example below relies on iron-router and presents a reactive approach for adding the active class
First should modify the template to be:
<a class="blog-nav-item {{active 'homePage'}}" href="{{pathFor 'homePage'}}">Home</a>
And then the appropriate helper for it should be:
Template.name.helpers({
active: function(routeName) {
var curRoute = Router.current().route;
return curRoute.name === routeName ? 'active' : '';
}
});
Edit v1.0+
As of iron-router 1.0, A route's name is now accessible at
route.getName() (previously it was route.name).
In particular, you'll need to write return
curRoute.getName() === routeName ? 'active' : '';
Thank you #jrbedard for the notification

I guess this would be the "Meteor way" you wanted:
<template name="menu">
<ul>
<li class="{{#if isCurrentPage 'pageA'}}active{{/if}}">
Page A
</li>
<li class="{{#if isCurrentPage 'pageB'}}active{{/if}}">
Page B
</li>
<li class="{{#if isCurrentPage 'pageC'}}active{{/if}}">
Page C
</li>
</ul>
</template>
Router.onBeforeAction(function(){
Session.set('currentRouteName', Router.current().route.name)
})
Template.menu.helpers({
isCurrentPage: function(pageName){
return Session.equals('currentRouteName', pageName)
}
})
Router.current().route.name do evaluate to the current page name in the latest version of iron router, but I don't know if that's part of the public API one should use.
EDIT
Router.current() is apparently reactive, so all JavaScript code you need is the following:
Template.menu.helpers({
isCurrentPage: function(pageName){
return Router.current().route.name == pageName
}
})

You can solve it with JavaScript only:
Template.header.events({
'click .blog-nav-item': function(event, template){
// Remove the class 'active' from potentially current active link.
var activeLink = template.find('.blog-nav-item')
if(activeLink){
activeLink.classList.remove('active')
}
// Add the class 'active' to the clicked link.
event.currentTarget.classList.add('active')
}
})

Related

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

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.

Materialize tabs persist active tab on page refresh

I am building a single page application using vue.js with materialize and I have a navbar with tabs to navigate to different pages on my website. Materialize's tabs has an active property that displays which tab is currently selected. Every thing this far works perfectly.
This is materialize's tabs reference
The Issue
If you refresh the web page the tabs active property 'resets' to its default position. So I am trying to figure out how to persist the state of the navbar's active property and then reassign it to router-link.
My Code
<ul id="tabs" class="tabs tabs-transparent" :class="{ 'navbar--color': !changeNavColor }">
<li class="tab" id="home">
<router-link
id="home"
class="link"
:class="{ 'navbar--color': !changeNavColor }"
to="/"
>Home</router-link>
</li>
<li class="tab" id="services">
<router-link
id="services"
class="link"
:class="{ 'navbar--color': !changeNavColor }"
to="Services"
>Service</router-link>
</li>
<li class="tab" id="Preapproved">
<router-link
id="Preapproved"
class="link"
:class="{ 'navbar--color': !changeNavColor }"
to="PreApproved"
>Get Pre-Approved</router-link>
</li>
<li class="tab">
<router-link
id="cars"
class="link"
:class="{ 'navbar--color': !changeNavColor }"
to="Cars"
>inventory</router-link>
</li>
<li class="tab">
<router-link
id="testimonials"
class="link"
:class="{ 'navbar--color': !changeNavColor }"
to="Testimonials"
>Testimonals</router-link>
</li>
</ul>
if (localStorage.currentTab) {
this.currentTab = localStorage.currentTab;
var activeTab = document.getElementById(this.currentTab);
activeTab.classList.add("active");
console.log("saved");
}
$(document).ready(function() {
$("a").click(function(event) {
this.currentTab = event.target.id;
console.log(this.currentTab);
});
});
$(document).ready(function() {
$(".tabs").tabs();
});
window.addEventListener("scroll", this.onScroll);
},
beforeDestroy() {
window.removeEventListener("scroll", this.onScroll);
},
watch: {
currentTab(newTab) {
console.log("watch");
localStorage.currentTab = this.currentTab;
}
}
any help is appreciated
So I think you can use hash mechanism by using window.location.hash. You can put the data-toggle attribute in every tag anchor. And just check for location.hash !== ''
But the more Vue way would be through client side storage. Check the link its from vue docs. Although it is for the input field but you will get the idea of how to persist info by keeping a reference in client storage and on reload getting your desired state from there onward. Hope it helps.
Remove the indicator that is nested inside the first li, and the navigation works fine.
<ul id="tabs" class="tabs tabs-transparent">
<li id="tab" class="tab">
Home
<li class="indicator"></li> <!-- THIS RANDOM NESTED INDICATOR IS THE ISSUE -->
</li>
<li id="tab" class="tab">
Service
</li>
<li id="tab" class="tab">
Get Pre-Approved
</li>
<li id="tab" class="tab">
inventory
</li>
<li class="indicator" style="right: 488px; left: 0px;"></li> <!-- CORRECT INDICATOR, AUTOMATICALLY GENERATED BY MATERIALIZE -->
</ul>
This is how I ended up implementing this. First all of your router-links or <a> have to have unique id's
mounted() {
if (localStorage.currentTab) {
this.currentTab = localStorage.currentTab;
var element = document.querySelector(this.currentTab);
element.classList.add("active");
}
$(document).ready(function() {
$(".tabs").tabs();
$("a").click(function(event) {
this.currentTab = "#" + event.target.id;
localStorage.currentTab = this.currentTab;
});
});
},
watch: {
currentTab(newTab) {
localStorage.currentTab = this.currentTab;
}
}

How to show and hide side menu in angular2

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

How to change a session variable when clicking on `<a>` in Javascript

I can't find a way to make it works without using PHP and I don't want to use PHP. The thing is that I have a list with some options :
And I want to set a session variable when I click on one link.
I have tried to do <a onClick="displayAllContainers();">All containers</a> then in my JS I have tried to do
`function displayAllContainers() {
console.log("Display all");
}`
But it didn't work.
[EDIT] This fiddle doesn't work but I can put all the code without making a question that make 500lines so
import { Template } from 'meteor/templating';
import { Session } from 'meteor/session'
import { InfosContainers } from '/both/collections/infosContainers.js';
import { InfosMachines } from '/both/collections/infosMachines.js';
import './main.html';
import '../imports/ui/controlPanel.js';
import '../imports/ui/container.js';
import '../imports/ui/machine.js';
import '../imports/ui/chart.js';
import '../imports/ui/controlPanel.html';
import '../imports/ui/container.html';
import '../imports/ui/machine.html'
if (Meteor.isClient) {
//subscribe the publication of the server
Meteor.subscribe('infosContainers');
Meteor.subscribe('infosMachines');
}
function displayAllContainers() {
console.log("Display all");
}
Template.body.onRendered(function () {
});
Template.body.helpers({
//return all objects of the collection machines with the specified state
infosMachines() {
return InfosMachines.find({});
},
//return all objects of the collection containers with the specified state
infos(state) {
return InfosContainers.find({stateContainer: state});
},
//return all containers
infosCtn(){
return InfosContainers.find({});
},
//return true if we have >=1 container running. It's the emergency button
urgence() {
return InfosContainers.find({stateContainer: 'running'}).count() > 0;
}
});
<!-- form containers -->
<div class="col-md-6 col-sm-12 col-xs-12">
<div class="x_panel">
<div class="x_title">
<h2>Containers</h2>
<ul class="nav navbar-right panel_toolbox">
<li><a class="collapse-link"><i class="fa fa-chevron-up"></i></a>
</li>
<li class="dropdown">
<i class="fa fa-wrench"></i>
<ul class="dropdown-menu" role="menu">
<li><a onClick="displayAllContainers();return false;">All containers</a>
</li>
<li>Only running containers
</li>
<li>Only paused containers
</li>
<li>Only stopped containers
</li>
</ul>
</li>
<li><a class="close-link"><i class="fa fa-close"></i></a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br/>
{{#each infosCtn}}
{{> container}}
{{/each}}
</div>
</div>
</div>
<!-- /form containers -->
You need to return false so as to prevent the default click behavior.
Just change this way:
<a onClick="displayAllContainers();return false;">All containers</a>
Try this,
HTML
<a onClick="displayAllContainers()" href="javascript:void(0);">All containers</a>
JS
function displayAllContainers() {
console.log("Display all");
}
EDIT
HTML
<a onClick="Meteor.call('displayAllContainers');
" href="javascript:void(0);">All containers</a>
JS
Meteor.methods({
'displayAllContainers': function(){
console.log("Hello world");
}
});
This works, JSFiddle
<script language="javascript">
function displayAllContainers(){
console.log("Display all");
}
</script>
<a onclick="displayAllContainers()">
All Containers
</a>
Write your function like below and it should work,
displayAllContainers = function(){
console.log("Display all");
}
I don't know why it works, I am putting a question for it, Will put link here. SO Question
Ok so thank you to everybody for you help because you have all helped me to found the solution and there is it :
1) I need to use template events in my JS
Template.body.events({
'click #anchorid': function (e) {
console.log("saucisse")
}
});
2) And I had to use the ID in the html but I can remove the onClick
<a id="anchorid">All containers</a>

How to add active class on current menu item page?

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.

Categories