There was a single dropdown it was working fine Now I want to make this code reusable, or create Directive because now there are few more dropdowns are added in few more pages
I prefer to make directive, but I am really stuck here
<div class="nav-item has-dropdown">
<div class="menu-text" (click)="hasDropdown($event)">
Click me
</div>
<div class="has-dropdown-view">
Dropdown contenthere
</div>
</div>
hasDropdown(event){
let target = event.target || event.srcElement || event.currentTarget;
this.dropownView = !this.dropownView;
if( this.dropownView ){
target.closest('.has-dropdown').classList.add('has-open')
}else{
target.closest('.has-dropdown').classList.remove('has-open')
}
};
stackblitz
How to implement this click function with the directive 'method'?
I think this could be a solution for your problem:
import { Directive,ElementRef, HostListener } from '#angular/core';
#Directive({
selector: '[hasDropdown]'
})
export class HasDropdownDirective {
constructor(private el: ElementRef) {
}
#HostListener('click') onMouseClick() {
//Place your code here
}
}
Well if you are using bootstrap in your project there is a better way of adding the open class in the dropdown.
Solution Bootstrap 3.3
HTML:
<ul class="nav navbar-nav navbar-right">
<li class="dropdown"
appDropDown>
<a href="#"
class="dropdown-toggle">Manage</a>
<ul class="dropdown-menu">
<li>
Save Data
</li>
<li>
Edit Data
</li>
</ul>
</li>
</ul>
Directivefile
import { Directive, ElementRef, HostListener, Renderer2, HostBinding, } from '#angular/core';
#Directive({
selector: "[appDropDown]",
})
export class DropdownDirective {
#HostBinding('class.open') isOpen: boolean = false;
constructor(private elRef: ElementRef, private renderer: Renderer2) {
}
#HostListener('click') click(eventData: Event) {
this.isOpen = !this.isOpen;
}
}
Note: Above solution uses the HostBinding method, you can even use the ElementRef for it.
This you automatically inject the class open on the click and you can keep using the same bootstrap template everywhere.
Related
I made a Multistep Drop Down Using UL and Li
code :
<li>{{dropdowntext}}
<ul>
<li>Exception on Leave</li>
<li>Performance Reward
<ul>
<li>Double Beat Working</li>
<li>Working on Weekly-Off/Holiday</li>
</ul>
</li>
</ul>
</li>
</ul>
Please see : https://stackblitz.com/edit/angular-7cwuuw?file=src%2Fapp%2Fapp.component.html
How do I take selected value from drop down using UL Li to the ts file .
I tried to do it using NgModule bit It did not work .
Please Look into this .
Since this is a pure CSS solution for a drop-down, NgModule wouldn't work because the vanilla HTML elements do not have those directives. However, you could assign a common template reference variable to all the anchor tags and assign a common event handler to them. Try the following
Template
<ul class="main-navigation">
<li><a #option href="#">Select</a>
<ul (select)="gg($event)" (change)="onChange($event)">
<li><a #option href="#">Exception on Leave</a></li>
<li><a #option href="#">Performance Reward</a>
<ul>
<li><a #option href="#">Double Beat Working</a></li>
<li><a #option href="#">Working on Weekly-Off/Holiday</a></li>
</ul>
</li>
</ul>
</li>
</ul>
Controller
import { Component, ViewChildren, ElementRef, Renderer2, QueryList } from '#angular/core';
export class AppComponent {
#ViewChildren('option', { read: ElementRef }) private options: QueryList<ElementRef>;
private onMouseUp = (data) => { console.log(data); }
constructor(private renderer: Renderer2) { }
gg(evwent){
alert("vdjv");
}
onChange(event) {
console.log(event);
}
ngAfterViewInit() {
this.options.forEach(option => {
this.renderer.listen(option.nativeElement, 'mouseup', () => {
this.onMouseUp(option.nativeElement.innerHTML);
});
})
}
}
I've modified your Stackblitz
Let's say I have an unordered list like so
<div>
<ul class="data-container">
<li #H1>00</li>
<li #H2>01</li>
<li #H3>02</li>
<li #H4>03</li>
<li #H5>04</li>
...
</ul>
</div>
What's the best way to get a element based on it's local variable using ViewChild then retrieving it's value and give it a special class (say class="active")
Is there a filter or find function I can use here?
Also, let's say I want to select one of the items, is there a better way than using (click)="SelectElement()" on all of them?
You can create a LiDirective to mark all LI. After that you can use all API provided my QueryList like find,filter, reduce, toArray ...
#Directive({
selector:'li'
})
export class LiDirective{}
#Component({
selector: 'my-app',
template: `
<div>
<h2>Hello {{name}}</h2>
<div>
<ul class="data-container">
<li>00</li>
<li #H2>01</li>
<li #H3>02</li>
<li #H4>03</li>
<li #H5>04</li>
</ul>
</div>
</div>
`,
})
export class App {
#ViewChildren(LiDirective, {read:ElementRef}) lis: QueryList<any>;
name:string;
constructor(private renderer: Renderer2) {
this.name = `Angular! v${VERSION.full}`
}
ngAfterViewInit() {
let second = this.lis.toArray()[2];
this.renderer.setStyle(second.nativeElement, 'color', 'blue');
}
}
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
I'm starting to use Firebase with AngularJS.
Coming from a php/serverside rendered pages.
I dont't get how we're supposed to hide parts of an app to some users.
I have basically 3 levels of users (guests / members / admins)
I could hide with a ng-show based on user, but this only hides client-side.
Data is still sent to the user
Real life example:
The menu items are different based on user level.
I was thinking about using ngshow and check for the uuid , but then again, is exposing the admins uuid a good idea? sounds terrible to me.
Then I thought about putting the menu inside a database and requesting the elements.
Not all users would access all items, but this means a lot of 'unauthorised access attempts on purpose'
What is the correct way of handling this? I feel like I've missed something important about client-only apps relying on Firebase services.
Look at userStatus method in service layer and it usage in other layers.
Service layer :
import { Injectable } from '#angular/core';
import { Observable } from 'rxjs/Observable';
import { AngularFireAuthModule, AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
#Injectable()
export class AuthService {
user: Observable<firebase.User>;
constructor(private fireAuth: AngularFireAuth) {
}
loginGoogle() {
this.fireAuth.auth.signInWithPopup(new firebase.auth.EmailAuthProvider())
.catch(function (error) {
alert('Please try again');
});
}
logout() {
this.fireAuth.auth.signOut();
}
userStatus() {
return this.fireAuth.authState;
}
}
Navbar Component :
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../../services/auth.service';
import { Observable } from 'rxjs/Observable';
import * as firebase from 'firebase/app';
#Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
user: Observable<firebase.User>;
constructor(private authservice: AuthService) {
this.user = this.authservice.userStatus();
}
ngOnInit() {
}
login() {
this.authservice.loginGoogle();
}
logout() {
this.authservice.logout();
}
}
And here is Navbar view, where you want to hide or show the elements based on if user is authenticated :
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
<a class="navbar-brand" routerLink="/">Firebase</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
<ul class="navbar-nav mr-auto">
<li class="nav-item ">
<a class="nav-link" routerLink="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" *ngIf="(user | async)?.uid" routerLink="/listings">Listings</a>
</li>
<li class="nav-item">
<a class="nav-link" *ngIf="(user | async)?.uid" routerLink="/add-listing">Add Listing</a>
</li>
</ul>
<ul class="navbar-nav navbar-right">
<li class="nav-item">
<a class="nav-link" *ngIf="!(user | async)?.uid" (click)="login()">Login</a>
<a class="nav-link" *ngIf="(user | async)?.uid" (click)="logout()">Logout</a>
</li>
</ul>
<div *ngIf="(user | async)?.uid">
<img src="{{(user | async)?.photoURL}}" style="width:30px;height:30px;">
<br> Email: {{(user | async)?.email}}
<br> Name: {{(user | async)?.displayName}}
</div>
</div>
</nav>
Let's say I have the following template:
<ul>
<li id="1" class="selectModal">First</li>
<li id="2" class="selectModal">Second</li>
<li id="2" class="selectModal">Third</li>
</ul>
How can I bind a click event by class in TypeScript, so when a li element is clicked I can get the element and query the ID or any other attribute of the clicked element?
There are many ways to do that. Straight forward solution:
<ul (click)="onClick($event.target)">
<li id="1" class="selectModal">First</li>
<li id="2" class="selectModal">Second</li>
<li id="2" class="selectModal">Third</li>
</ul>
onClick(e:HTMLElement){
console.log(e.id, e.className);
}
Yes, you can, but it depends on the strategy. You could do it by JQuery or using the DOM accessors. In my team we use JQuery but we don`t search the entire DOM to find the elements, instead, we use a class called ElementRef:
import { ElementRef } from '#angular/core';
...
constructor(private elementRef : ElementRef) {
}
ngAfterViewInit() {
jQuery(this.elementRef.nativeElement).find('selectModal').on('click', () => {
//do something here
});
}
The ElementRef class is a reference for the component itself in the DOM. So we're able to filter the search to this component.