How do I update Angular styling using ElementRef? - javascript

I am new to Angular I am working on a bottom that updates the styling when pressed. Here is a copy of the HTML page.
<nav>
<button #toggleNavigation aria-expanded="false">
<mat-icon>menu</mat-icon>
</button>
<div class="sidebar-sticky collapse navbar-collapse">
<ul>
<side-menu-item *ngFor="let item of navItems" [hidden]="item.isHidden"
[finished]="item.finished" [name]="item.displayName"
[routeURL]="item.routeURL"
[ngClass]="{'mt-auto': item.name === 'Summary'}">
</side-menu-item>
</ul>
</div>
</nav>
When the button is pressed, this is what I would like it to update to.
<nav>
<button #toggleNavigation aria-expanded="true">
<mat-icon>menu</mat-icon>
</button>
<div class="sidebar-sticky collapse navbar-collapse show">
<ul>
<side-menu-item *ngFor="let item of navItems" [hidden]="item.isHidden" [finished]="item.finished" [name]="item.displayName" [routeURL]="item.routeURL" [ngClass]="{'mt-auto': item.name === 'Summary'}"></side-menu-item>
</ul>
</div>
</nav>
Clicking the button will display a navigation list. As you see in the code the styling is updated from class="sidebar-sticky collapse navbar-collapse" to class="sidebar-sticky collapse navbar-collapse show". Originally, I using a bootstrap.js file to handle this but it interfered with styling associated with another program. In my .ts file this is what I have
import { Component, ElementRef, Renderer2, ViewChild } from '#angular/core';
#Component({
selector: 'app-side-menu',
templateUrl: './side-menu.component.html',
styleUrls: ['./side-menu.component.scss']
})
export class NavMenuComponent {
#ViewChild('toggleNavigation', {static: false}) toggleNavigation: ElementRef;
constructor() {
onToggleNavigation() {
}
}
Any help would be greatly appreciated.

I would do this with [ngClass].
Try:
<nav>
<button #toggleNavigation aria-expanded="true" (click)="onToggleNavigation()">
<mat-icon>menu</mat-icon>
</button>
<div class="sidebar-sticky collapse" [ngClass]="{'show': !collapseSideNav}">
<ul>
<side-menu-item
*ngFor="let item of navItems"
[hidden]="item.isHidden"
[finished]="item.finished" [name]="item.displayName"
[routeURL]="item.routeURL"
[ngClass]="{'mt-auto': item.name === 'Summary'}"
(click)="collapseNavigation()"
>
</side-menu-item>
</ul>
</div>
</nav>
collapseSideNav: boolean = true; // can default it to whatever you like
onToggleNavigation() {
this.collapseSideNav = !this.collapseSideNav;
}
collapseNavigation() {
if (!this.collapseSideNav) {
this.collapseSideNav = true;
}
}

Use [ngClass] for this:
<nav>
<button [attr.aria-expanded]="collapsed" (click)="collapsed = !collapsed">
click
</button>
<div [ngClass]="{'show' : collapsed}" class="sidebar-sticky collapse navbar-collapse">
<ul>
content
</ul>
</div>
</nav>
https://stackblitz.com/edit/angular-3rn8no?file=src%2Fapp%2Fapp.component.ts

Related

Programmatically Collapse Bootstrap Navbar in Typescript

I'm using Bootstrap's navbar and I can get it to collapse successfully by using data-toggle and data-target on each li element.
This SO answer shows a way to do this without having to alter each li:
https://stackoverflow.com/a/42401686/279516
This is my navbar with two of the li elements:
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item" data-toggle="collapse" data-target=".navbar-collapse.show">
<a class="nav-link" href="#" routerLink="/servers">Servers</a>
</li>
<li class="nav-item" data-toggle="collapse" data-target=".navbar-collapse.show">
<a class="nav-link" href="#" routerLink="/servers">Variables</a>
</li>
I'm close to getting this done in my Angular 8 Typescript file:
export class AppComponent implements OnInit {
ngOnInit(): void {
const navbarItems = document.querySelectorAll('.navbar-nav>li');
navbarItems.forEach(navbarItem => {
navbarItem.addEventListener('click', () => {
const navbar = document.querySelector('.navbar-collapse').collapse('hide');
})
});
}
}
The issue is the last line:
Property collapse does not exist on type element.
First, what should I do to get this to work?
Second, is there a better way?
I've tried casting navbar as different types of HTML elements, but that doesn't work either.
You can do it more the Angular way. Like this:
<button class="navbar-toggler" type="button" (click)="showMenu=!showMenu">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" [ngClass]="{'show':showMenu}">
...
</div>
I was able to get it to work by removing 'show' from the class list, shown on the last line here.
(I'm still not sure if this is a good approach, but it's working.)
export class AppComponent implements OnInit {
ngOnInit(): void {
const navbarItems = document.querySelectorAll('.navbar-nav>li');
navbarItems.forEach(navbarItem => {
navbarItem.addEventListener('click', () => {
const navbar = document.querySelector('.navbar-collapse');
navbar.classList.remove('show');
})
});
}
}

Maximum update depth exceeded when trying to setState when user clicks

I am trying to When user clicks on list set a state
I have listing in li tag in a loop when user click one of li tag i want to update some state but react throws error.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested
Here my main piece of code:
class Header extends React.Component{
constructor(props){
super(props);
this.showCatDetail=this.showCatDetail.bind(this);
this.state={
category:[],
clk_category:[],
detail:false
}
}
componentDidMount() {
fetch('http://127.0.0.1:8000/portfolio/create_category/')
.then(response=>response.json())
.then(categoryJson => this.setState({category: categoryJson},()=>{
this.sortCategory()
}))
}
showCatDetail=(e)=>{
e.preventDefault();
this.setState({detail:true,clk_category:JSON.parse(e.currentTarget.getAttribute('data-item'))},()=>{
console.log(this.state.clk_category)
});
};
sortCategory = ()=>{
let sortArray=this.state.category;
let swap;
for (let i=0;i<sortArray.length;i++)
{
for (let j=0;j<sortArray.length;j++){
if(sortArray[i].category_rank>sortArray[j].category_rank){
swap=sortArray[i];
sortArray[i]= sortArray[j];
sortArray[j]=swap;
}
}
}
this.setState({category:sortArray})
};
render(){
let hreflink=null;
let redirect=null;
if (this.state.detail){
redirect=<Redirect to={`/category_project/${this.state.clk_category.id}`}/>
}
return(
<div>
{redirect}
<header id="header">
<div id="trueHeader">
<div className="wrapper">
<div className="container">
<div className="logo">
<a href={hreflink} id="logo">
</a>
</div>
<div className="menu_main">
<div className="navbar yamm navbar-default">
<div className="container">
<div className="navbar-header">
<div className="visibledevice">
<ul className="nav navbar-nav">
<li><a href={hreflink} className="active">
<i className="fa fa-home">
</i> Home</a></li>
</ul>
</div>
</div>
<div className="navbar-collapse collapse pull-right">
<ul className="nav navbar-nav">
<li><a href={hreflink} className="active">
<i className="fa fa-home">
</i> Contact Us</a></li>
{this.state.category.map(cat=>{
return(
<li data-item={JSON.stringify(cat)} onClick={(e)=>this.showCatDetail(e)}><a href={hreflink} >
<i className="fa fa-home">
</i>{cat.category_name}</a></li>
)
})}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</header>
</div>
)
}
}
I can't figure out what the problem is...
onClick={(e)=>{this.showCatDetail(e)}}
Try this in onclick

hide menu when page loads, onclick button show menu, first click show, second click hide, like toggle in angular 4.0

I am working on navigation default when page loads navigation should be hide. When I click on icon I want to show navigation like toggle. when I mouse out from navigation I should hide navigation. angular 4.0.
index.html
<button class='user_login' (click)='btnResult()'>
<img src="./assets/menuicon.png" >
</button>
nav.component.html
<ul class="nav navbar-nav navbar-right menu" *ngIf="menu">
<li ><a routerLink="one">one</a></li>
<li><a routerLink="two">two</a></li>
<li><a routerLink="three">three</a></li>
<li><a routerLink="four">four</a></li>
<li><a routerLink="five">five</a></li>
<li><a routerLink="six">six</a></li>
</ul>
nav.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {
menu = false;
constructor() {
btnResult(){
this.menu = true;
}
}
ngOnInit() {
}
}
component.html
<button (click)="toggle()" id="bt">
{{buttonName}}
</button>
<ng-container *ngIf="show">
<div style="margin: 0 auto;text-align: left;">
<div>
<label>Name:</label>
<div><input id="tbname" name="yourname" /></div>
</div>
<div>
<label>Email Address:</label>
<div><input name="email" id="email" /></div></div>
<div>
<label>Additional Information (optional):</label>
<div><textarea rows="5" cols="46"></textarea></div>
</div>
</div>
</ng-container>
component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
public show:boolean = false;
public buttonName:any = 'Show';
ngOnInit () { }
toggle() {
this.show = !this.show;
// CHANGE THE NAME OF THE BUTTON.
if(this.show)
this.buttonName = "Hide";
else
this.buttonName = "Show";
}
}
The wheel has already been invented!
Google "Bootstrap Collapsing Navbar", and you'll find many ways to make your life simpler with the Bootstrap 3 CSS & jQuery library.
You should probably take a look at event bindings (Angular Event Bindings).
Create a function in the component's logic which binds to the element's mouseleave:
Template:
<ul (mouseleave)="hideMenu()">[...]</ul>
Component:
mouseleave(): void {
this.menu = false
}
Update:
app-nav.component.html:
<button (click)="showNavigationMenu()">Show</button>
<ul *ngIf="menuVisible" (mouseleave)="hideNavigationMenu()">
[...]
</ul>
app-nav.component.ts:
menuVisible: boolean
constructor() { this.menuVisible = false }
showNavigationMenu(): void {
this.menuVisible = true
}
hideNavigationMenu(): void {
this.menuVisible = false
}
Plunker: Plunker
I hope this will help you.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Bootstrap menu</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Lato" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNavbar">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#myPage">Logo</a>
</div>
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="nav navbar-nav navbar-right">
<li>ABOUT</li>
<li>SERVICES</li>
<li>PORTFOLIO</li>
<li>PRICING</li>
<li>CONTACT</li>
</ul>
</div>
</div>
</nav>
</body>
</html>

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

Set default tab to Angular.js tabs

I have an Angular.js component which has a list of tabs. When a tab is clicked I assign an ng-classto it (active), so it gets highlighted. This is working fine, but I also want the first tab to be the default active one when a user first load the page, but at the moment nothing is highlighted when I load the page.
Here's my component:
'use strict';
angular.module('menuBar').component('menuBar', {
templateUrl: 'menu-bar/menu-bar.template.html',
controller: function menuBarController() {
this.menus = [
{
name: 'Tab1'
}, {
name: 'Tab2'
}, {
name: 'Tab3'
}, {
name: 'Tab4'
}, {
name: 'Tab5'
}
];
this.tab = this.menus[0].name;
this.setTab = function (tabId) {
this.tab = tabId;
}
this.isSet = function (tabId) {
return this.tab === tabId;
}
}
});
Here my html template:
<div class="navbar navbar-inverse navbar-collapse">
<div class="container">
<ul class="nav nav-tabs">
<li ng-repeat="menu in $ctrl.menus" ng-class="{active:tab.isSet(menu.name)}">
<a href ng-click="tab.setTab(menu.name)">{{menu.name}}</a>
</li>
</ul>
</div>
</div>
Maybe something wrong at this line here where I'm trying to set my default tab?
this.tab = this.menus[0].name;
Update: Plunker added
Live preview here
<div class="navbar navbar-inverse navbar-collapse">
<div class="container">
<ul class="nav nav-tabs">
<li ng-repeat="menu in $ctrl.menus" ng-class=" active:menu.name==$ctrl.tab}">
<a href ng-click="$ctrl.setTab(menu.name)">{{menu.name}}</a>
</li>
</ul>
</div>
You can use orderBy:
Function: A getter function. This function will be called with each item as argument and the return value will be used for sorting.
I'm not sure about the syntax since I haven't used components yet but something among the lines:
<div class="navbar navbar-inverse navbar-collapse">
<div class="container">
<ul class="nav nav-tabs">
<li ng-repeat="menu in $ctrl.menus | orderBy: $ctrl.isSet(tab.id)" ng-class="{active:tab.isSet(menu.name)}">
<a href ng-click="tab.setTab(menu.name)">{{menu.name}}</a>
</li>
</ul>
</div>
</div>

Categories