I want to hide a Dropdown (it's elements included) on a certain page. I'd do it with a '*ngIf'-request, however I'm not sure about the condition.
The router path is '/project' but I can't access it - therefore *ngIf="path==='/project'" won't work.
Any ideas on what condition should be used? Or a better solution to the problem.
There also are subpaths like /project/id, on which the Dropdown should be available.
In your component/controller, try something like:
showDropdown: boolean = false;
ngOnInit() {
this.showDropdown = path === '/project'
}
path is maybe a Input-variable of your component?
#Input
path: string;
In your HTML-Template, you do something like:
<div *ngIf="showDropdown">test</div>
In your controller, add a boolean visible ( true or false )
and in you html simply add : *ngIf="visible" to your div
As I understood your situation, you need to do the following:
In the navigation bar component you have to subscribe to routing to get the current path which will help you to realize whether show or not your dropdown, do the following
import { Router, NavigationEnd } from '#angular/router';
public showDropDown: boolean;
constructor(private router: Router) {}
...
ngOnInit() {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.showDropdown = event.url.indexOf('/project') >= 0;
}
}
}
In your html where your dropdown is present
<div class="my-dropdown" *ngIf="showDropdown">
... (your dropdown)
</div>
this will help you to avoid dependencies from other components and be able to manipulate data according to routing. Surely there will always be a way to improve this. Everything depends on what you want as a result.
Related
I have an article-map component. In it, with the help of the ngFor directive, I display brief information about the articles. I call the "article-map" component in the "feed" component. The "feed" component should have three views with different "article-map" styling. For example: the first one is a sheet, the second one is two columns, etc. How do I style the article-map component for different feed views using ngClass?
I started with the following. In article-card.component.ts I set a variable to get the parameter from the link.
export class ArticleCardComponent implements OnInit {
constructor(private route: ActivatedRoute) { }
typeView='default';
ngOnInit(): void {
this.route.queryParams.subscribe(params => {
console.log(params)
this.typeView=params['viewType'];
})
}
}
Now I want to write a ternary expression for ngClass that will allow different style classes to be used for feed views. Tell me how to do it?
In your case it will be.
<div [ngClass]="typeView === 'default' ? 'css-class-1' : 'css-class-2'">
If you want more than one condition write a function like
html
<div [ngClass]="getClass()">
ts
getClass() {
switch(this.typeView) {
case 'default':
return 'css-class-1';
case 'special':
return 'css-class-2';
default:
return 'css-class';
}
}
Im searching the best way to show/hide components on my angular application using the current location path like, homepage, loginpage, logoutpage, etc.
I'm suscribed to the router events that gives me the current path, so If Im in the login page I should hide the "navbar-component" and if I'm in the home page I should show it.
This approach should work with different components in different current pages. So I was thinking in this method inside of a *ngIf:
app.component.html
<nav *ngIf="myService.isComponentPartOfTheCurrentPage('navbar')">
...some navigation buttons here
</nav>
myService.ts
isComponentPartOfTheCurrentPage(componentName: string): boolean {
const url = getCurrentPath(); // This works fine
return currenPathContainsThisComponent(componentName, url); // This is gonna return true or false.
}
The main problem with this approach is that the angular cycling is calling this function a lot of times. Also I've read some blogs that not recommend this king of things.
Is there a better way to accomplish this?
In the subscription to your route events update a behavior subject on the service with the current
section$ = new BehaviorSubject(null);
in your route sub
sections$.next(section);
then in your component you listen to the behaviour subject with the async pipe
section$ = this.service.section$;
and in the template
<nav *ngIf="section$ | async as section">
<div *ngIf="section === 'navbar'">Something</div>
</nav>
The section variable will imagically update each time the behavior subject emits.
You could watch for router events, specifically NavigationEnd, assign the current route to an observable and then do the checks in the components for what route we are currently on.
Service:
import { Router, NavigationEnd } from "#angular/router";
import { filter, map } from "rxjs/operators";
currentRoute$: Observable<string>;
constructor(private router: Router) {
this.currentRoute$ = router.events.pipe(
filter(e => e instanceof NavigationEnd),
map((e: NavigationEnd) => e.url)
);
}
Then listen to the observable using async pipe and do the checks
*ngIf="(myService.currentRoute$ | async) === '/login'"
You can also perhaps use includes if you need to check that if that url fragment is included in url, you can then do:
*ngIf="(myService.currentRoute$ | async).includes('login')
I'm making a pop-up component that I want to use in several of my other components, so I made a popup.service that enable the component to be loaded through *ngIf inside other components. This is creating a problem for me since the PopupComponent is a separate entity and I'm unsure how to pass data from the child component(PopupComponent) to its respective parents.
Atm the loading looks like this in ParentComponent.ts:
public openPopup(order_id: string, invoice_id: string): void{
this.load_popup=this.popupService.openPopup(order_id, "selected_order", invoice_id, "selected_invoice");
}
And ParentComponent.html:
<app-popup *ngIf="load_popup"></app-popup>
And it loads like a charm, the problem is in closing it. The close button is located on the PopupComponent, is there an efficient way to have the Child Component (PopupComponent) to affect a variable in the Parent Component ie. ParentComponent.load_popup=false?
My other thought was dynamically loading the component, however I have no idea on how to do that. I was fidgeting around with using the PopupService and putting something like this in it:
import { Injectable, ComponentRef } from '#angular/core';
import {PopupComponent} from '../popup/popup.component';
#Injectable({
providedIn: 'root'
})
export class PopupService {
popup_ref: ComponentRef<PopupComponent>
constructor(
) { }
//Implemented in orderoverviewcomponent, invoicecomponent, and placeordercomponent
public openPopup(id1:string, storage_label1:string, id2:string, storage_label2:string): Boolean{
if (id1){
localStorage.setItem(storage_label1, JSON.stringify(id1));
}
if (id2){
localStorage.setItem(storage_label2, JSON.stringify(id2));
}
this.popup_ref.initiate(); //this line is a made up example of loading the component
return true;
}
public closePopup(storage_label1: string, storage_label2:string): Boolean{
if(storage_label1){
localStorage.removeItem(storage_label1);
}
if(storage_label2){
localStorage.removeItem(storage_label2);
}
this.popup_ref.destroy();
return false;
}
}
Where this.popup_ref.destroy(); would ideally destroy PopupComponent, but when I did that I got a "cannot read property of undefined" on the popup_ref, I'm having trouble declaring it, the syntax seems a bit tricky.
The problem also remains that i need a function to load the component, the opposite of .destroy(), if this is possible I would much prefer it over loading and destroying with *ngIf.
Edit: Partially solved it by just using a boolean in the service as the trigger for *ngIf, is there a way to do a function load and destroy on a component still?
You can bind an EventEmitter() to your component to invoke a function in the parent component.
<app-popup [onClose]="load_popup = false" *ngIf="load_popup"></app-popup>
Then inside of your app-popup component:
#Output onClose = new EventEmitter();
public closePopup(/* code emitted for brevity */) {
/* code emitted for brevity */
this.onClose.emit(); //Call the parent function (in this case: 'load_popup = false')
}
It's important to know that you can pass entire functions to the bound function, and you can even pass variables back to the parent from the child:
[onClose]="myFunction($event)"
this.onClose.emit(DATA HERE);
As an aside, since you're using Angular; I would suggest looking into using Modals for popup dialogue boxes. You can see a good example here:
https://ng-bootstrap.github.io/#/components/modal/examples
I have a situation in Angular 4.0.3 where I have two <router-outlet>'s on a page.
<router-outlet></router-outlet>
<router-outlet name="nav"></router-outlet>
The first outlet will accept routes for content, and the second will accept routes for navigation. I achieve the navigation using this;
router.navigate(['', {outlets: { nav: [route] } }],{skipLocationChange: true });
This changes the outlet's contents without updating the URL - since I don't want any url that look like .. (nav:user).
The problem is the remaining outlet. I do want the URL to update when those are clicked, for instance ...
.../user/profile
Functionally, I can get both outlets to have the proper content, but it keeps appending the nav outlet's route to the url, like this ...
.../user/profile(nav:user)
Is there any way I can stop it from adding the (nav:user) part?
Unless there is some trick I'm not aware of ... I don't think you can. The address bar is what maintains the route state. So without the secondary outlet information in the address bar, the router won't know how to keep the correct routed component in the secondary outlet.
You could try overriding the navigateByUrl method as shown here: http://plnkr.co/edit/78Hp5OcEzN1jj2N20XHT?p=preview
export class AppModule { constructor(router: Router) {
const navigateByUrl = router.navigateByUrl;
router.navigateByUrl = function(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}): Promise<boolean> {
return navigateByUrl.call(router, url, { ...extras, skipLocationChange: true });
} } }
You could potentially add logic here then to check which routes you need to do this on.
I have a component that's called in different areas of my site which has more components nested inside of it that I want to display depending on the route. I came up with this solution.
import { Component } from '#angular/core';
var routeLocation = window.location.pathname;
#Component({
selector: 'asset-packs',
template: `<h1>Asset Packs</h1>
<asset-expand *ngIf="routeLocation.indexOf('expand') > 0"></asset-expand>
<asset-newbus *ngIf="routeLocation.indexOf('rebrand') > 0"></asset-newbus>
`
})
export class PointAssetsComponent {
}
my intention was to use
var routeLocation = window.location.pathname;
to pull the url from the browser and save it into a variable which I could then call in the *ngIf statement as
*ngIf="routeLocation.indexOf('expand') > 0"
As you can see from the quoted out variables I've tried a few different ways of accessing the URL as well as swapping the exact text I want to look for for a variable with the text stored in it. Either which way I'm getting the undefined error.
So far I haven't been able to find any examples of
.indexOf()
specifically being used in ngular 2, but from what I've seen about it I'm using the right syntax with it. I was originally trying to use
.contains()
and got the same error. When I delete the ngIf statements both components show up without a problem. It's just when I add them in that this problem starts occurring.
I've come across a few other articles on this issue where they said it was a bug caused by AngularFire and FireBird modules in Node. I checked and neither of those are in my app.
The only thing I figure is it has to be something with the syntax or I'm not importing something that makes the
window.location.etc
parts work. Does anybody know what's causing this and how to fix it?
You could do this in your ts file:
import { Router } from '#angular/router';
export class PointAssetsComponent {
public navExpand:boolean = false;
public navRebrand:boolean = false;
constructor(private router: Router) {
}
if (this.router.url.substring(0,7) === '/expand'){
this.navExpand = true;
} else if (this.router.url.substring(0,8) === '/rebrand'){
this.navRebrand = true;
}
HTML
#Component({
selector: 'asset-packs',
template: `<h1>Asset Packs</h1>
<asset-expand *ngIf="navExpand"></asset-expand>
<asset-newbus *ngIf="navRebrand"></asset-newbus>
`
})