Angularjs 4 - Need to refresh for display/hide directive - javascript

I have a problem to hide the navbar when the user is not logged in (on the public views), I check if the item currentUser exists on the localStorage and then I use
*ngIf on the html template to show/hide.
When I login at first I don't see the navbar, but after refreshing the page it's displaying, the same when I logout, at first it shows it and after refreshing the page it's gone.
There is my app.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
moduleId: module.id,
selector: 'app',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
userLogged = JSON.parse(localStorage.getItem('currentUser'));
ngOnInit() {
console.log(this.userLogged);
}
}
And my app.component.html
<!-- main app container -->
<div class="jumbotron">
<div class="container">
<ng-navbar *ngIf="userLogged"></ng-navbar>
<div class="col-sm-12">
<alert></alert>
<router-outlet></router-outlet>
</div>
</div>
</div>
In case you need more information just ask for it, is my first Angularjs 4 question and I don't know what to show exactly.

Try this:
<ng-navbar *ngIf="userLogged()"></ng-navbar>
userLogged() { return JSON.parse(localStorage.getItem('currentUser')) };

Related

System dialog Angular Material

I work for system of dialog (Angular Material).
I create dialog-service for controll and container dialog. Dialog-service has methods for open/show different dialoges.
And I create dialog-component for contain data for dialog (it is single component of dialog). It is universal component.
I add StackBlitz
I have problem with closing dialoges after callback.
How I can close dialog after callback? I try using [mat-dialog-close] - but I was not able to somehow parameterize - enable and disable the [mat-dialog-close] of different buttons.
And a have little problem. How I can add dynamicly mat-button to button element?
(I add class 'mat-button', but this don't full imitation mat-button)
<div *ngIf="getButtons().length > 0 || getCloseButton()" mat-dialog-actions>
<ng-container *ngFor="let button of getButtons()">
<button [attr.class]="button.class"
(click)="button.callback(button.callbackItem || dialogForm)">{{button.title}}</button>
</ng-container>
</div>
In your dialog.html you must have something like this:
<button mat-stroked-button (click)="closeDialog()">Close</button>
and in your dialog.ts:
import { Component, OnInit, Inject } from '#angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '#angular/material';
#Component({
selector: 'dialog',
templateUrl: './dialog.component.html',
styleUrls: ['./dialog.component.scss']
})
export class DialogComponent implements OnInit {
constructor(public dialogRef: MatDialogRef<DialogComponent>) { }
ngOnInit() {
}
closeDialog() {
this.dialogRef.close();
}
}

Angular 7 Url changes but nothing else happens

This is the first time I post here, I'm quite desperate.
Im using Angular 7. The problem is that when I manually type the desired url, it works well, but when I press a button and use RouterLink, the url changes but nothing else happens. If I press F5, the page will reload and will go to that new URL that has changed without trouble, so it's not a url routing problem.
I only implemented the routerLink in two buttons for the moment (in cities-nav), while I test it.
I also implemented a temporary one in app-component.html just in case it was a Material menu problem, but it doesn't work either.
Console says nothing. And I have a console.log inside the onInit of the cities-nav component, which triggers the first time that loads the web, but not when I use routerLink, so it doesn't even get there.
I also tried executing a method with a (click) event. Doesn't work either.
My code is the following:
My app.component.html
<div style="text-align:center">
<nav>
<a routerLink="/">Go home</a>
</nav>
</div>
<router-outlet></router-outlet>
This is my app-routing.module
import { NgModule } from "#angular/core";
import { Routes, RouterModule } from "#angular/router";
import { CitiesNavComponent } from './cities-nav/cities-nav.component';
const routes: Routes = [
{ path: "", redirectTo: "cities/Madrid", pathMatch: "full" },
{ path: "cities/:name", component: CitiesNavComponent }
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
This is my cities-nav.component.html
<div class="container">
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<span *ngIf="cityName" class="mdl-layout-title">{{this.cityName}}</span>
<div class="mdl-layout-spacer"></div>
</div>
</header>
<div class="mdl-layout__drawer">
<span class="mdl-layout-title">Cities</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" routerLink="/cities/Madrid" routerLinkActive="active">Madrid</a>
<a class="mdl-navigation__link" routerLink="/cities/Barcelona">Barcelona</a>
<a class="mdl-navigation__link" (click)="goToCadiz()">Valencia</a>
<a class="mdl-navigation__link" href="">Cádiz</a>
<a class="mdl-navigation__link black-text" href="">ABOUT</a>
</nav>
</div>
<main class="mdl-layout__content">
<div class="page-content"><app-content *ngIf="cityName" [cityName]="this.cityName"></app-content></div>
</main>
</div>
</div>
This is my cities-nav.component.ts
import { Component, OnInit, NgZone } from "#angular/core";
import { Location } from "#angular/common";
import { ActivatedRoute } from "#angular/router";
import { Router } from "#angular/router";
#Component({
selector: "app-cities-nav",
templateUrl: "./cities-nav.component.html",
styleUrls: ["./cities-nav.component.scss"]
})
export class CitiesNavComponent implements OnInit {
cityName: string;
constructor(
private location: Location,
private route: ActivatedRoute,
private router: Router,
private ngZone: NgZone
) {}
ngOnInit() {
console.log("Cities nav component OnInit executed");
this.cityName = this.route.snapshot.paramMap.get("name");
}
goToCadiz() {
this.ngZone.run(() => {
this.router.navigateByUrl('/cities/Cadiz');
});
}
}
First screenshot of tracing
Second screenshot of tracing
Okay, after a long time I found out what was happening. I actually had two problems.
First one, I had to change this line in cities-nav.component:
this.cityName = this.route.snapshot.paramMap.get("name");
To:
this.activeRoute.params.subscribe(routeParams => {
this.cityName = routeParams.name;
})
Because I always was on the path 'cities/:name', so even if I changed from one city to another, it didn't get the name again from the input. So that subscribe solves the problem, and will give you the new param every time you change the variable inside the same path.
The other problem was inside the app-content, because inside onInit I called the cityService which got a city by a name. The problem was similar to the other one, it only reached the city once, even if the city input name changed. So the solution was creating a method ngOnChanges as follows:
ngOnChanges(changes: SimpleChanges): void {
//Add '${implements OnChanges}' to the class.
this.getCityByName(this.cityName);
}
This way every time the component input 'cityName' changes, it will get the new city and update.
console log in the ngOnInit will be called only once.If you want to detect change in the parameters then subscribe to the paraMap in activateRoute.
created a sample demo in the link below.
https://stackblitz.com/edit/angular-mriyze?file=src%2Fapp%2Fcities-nav.component.ts

Angular 4 show popup onclick by other component

i'm struggling about this problem and can't figure out.
I simply need to show a popup div situated in the page clicking from a menu entry in my navbar.component.
I added a property "show" in my popup which prints the "show" class on my div using the ngClass (with if) directive. I can get this working if the action button is inside my popup component but i cannot print the show class clicking on another component. The property in the Object get updated but the class is not printed. I'm using angular 4 with ng-bootstrap. I tried both with services and with parent/child emit event.
This is is my situation:
app.component.html
<app-nav-bar></app-nav-bar>
<app-login></app-login>
<router-outlet></router-outlet>
<app-footer></app-footer>
navbar.component.html
...
<button class="dropdown-item" (click)="showPopup()">LOGIN</button>
...
navbar.component.ts
import {Component, EventEmitter, Input, OnInit, Output} from '#angular/core';
#Component({
moduleId: module.id,
selector: 'app-nav-bar',
templateUrl: 'navbar.component.html',
styleUrls: ['./navbar.component.css'],
})
export class NavbarComponent implements OnInit {
#Output() show = new EventEmitter<boolean>();
ngOnInit() {
}
showPopup() {
this.show.emit(true);
}
}
login.component.html
<div id="wrapper-login-popup" class="fade-from-top" [(class.show)]="show">
<div id="container-login-popup">
<div class="row">
<div class="col-sm-12 text-center">
<img id="popup-bomb" src="assets/images/bomb.png" alt="bomb"/>
<img id="popup-close" class="close-icon" src="assets/images/close.png" alt="close"
(click)="closePopup()"/>
</div>
</div>
</div>
</div>
login.component.ts
import {Component, Input, OnInit} from '#angular/core';
import {AuthService} from '../services/auth.service';
import {IUser} from './user';
#Component({
selector: 'app-login',
templateUrl: 'login.component.html',
styleUrls: ['login.css']
})
export class LoginComponent implements OnInit {
private username: string;
private password: string;
#Input() show: boolean = false;
constructor(private AuthService: AuthService) {
}
ngOnInit() {
}
login() {
...
}
showPopup() {
console.log(this); //Show is false
this.show = true;
console.log(this); //Show is true but does not trigger the show class
}
closePopup() {
this.show = false;
}
}
The issue here is that your nav-bar and login components are siblings and can't directly communicate with each other. You have show as an output of navbar and as an input of login, but you haven't connected the dots.
You need to update your app.component to connect them.
export class AppComponent implements OnInit {
show = false;
onShow() { this.show = true; }
}
and in the template:
<app-nav-bar (show)="onShow()"></app-nav-bar>
<app-login [(show)]="show"></app-login>
There's a lot of two way binding going on here which works for something simple liek this, but generally it's a bad idea as it leads to unmaintainable code. You should choose one owner of the show variable and force all changes to it through him. In this case the app component is the most logical owner, so I'd change the login component to emit an event that changes the show variable in app component adn remove all 2 way bindings, but in a bigger app, you may even want a separate service that manages hiding/showing pop ups. This eliminates the need for the sending a message up and down your component tree, you can inject the service where it's needed.
As another commenter mentioned, you also should be using ngClass for class manipulation like
[ngClass]="{'show':show}"
a service based solution would look like
import {Subject} from 'rxjs/Subject';
#Injectable()
export class PopUpService {
private showPopUpSource = new Subject();
showPopUp$ = this.showPopUpSource.asObservable();
showPopUp() { this.popUpSource.next(true); }
closePopUp() { this.popUpSource.next(false); }
}
Then you provide in app module or at app component level:
providers:[PopUpService]
make sure you don't re provide this later, as you only want one copy to exist so everyone shares it.
then inject into both components, and have them call the services close or show pop up methods.
then in the login component you bind to the popUp$ observable like
constructor(private popUpSvc:PopUpService){}
show$;
ngOnInit() { this.show$ = this.popUpSvc.showPopUp$; }
showPopUp() { this.popUpSvc.showPopUp(); }
closePopUp() { this.popUpSvc.closePopUp(); }
and in the template subscribe w async pipe like
<div id="wrapper-login-popup" class="fade-from-top" [ngClass]="{'show': (show$ | async) }">
The reason for using the async pipe is garbage collection managemetn is simpler. If you don't use async, you need to garbage collect manually in ngOnDestroy by calling unsubscribe(), otherwise your subscriptions will keep stacking up. There is also a more nuanced benefit in that the async pipe triggers change detection, but this only becomes important if you start using onPush change detection for performance optimization.

Change color of div based on page selection in Angular 4

new to Angular so please bear with me (or just point me to the appropriate docs article if this is just that obvious)
Basically, the structure of my site (for all of the pages) is this:
navigation (home, about, resources, contact)
header-div
content
footer
I want it so that any of the links you click will change the contents of the header-div; for now I'll start with changing the background color. For example, the home page's header is blue, about is red, resources is green, contact is yellow.
What I started doing but got stuck with was directly manipulating the style by using a method and click listener on the links
How would I got about attaching a class to the div, based on the link that's been clicked?
This is my app.component.ts
import { Component } from '#angular/core';
import { RouterModule, Routes } from '#angular/router';
#Component({
selector: 'app-root',
template: `
<div class="app-nav">
<nav class="set-margin">
<ul>
<li><a routerLink="/" routerLinkActive="active" (click)="showStyle = !showStyle">Home</a></li>
<li><a routerLink="/about" routerLinkActive="active">About</a></li>
<li><a routerLink="/resources" routerLinkActive="active">Resources</a></li>
<li><a routerLink="/contact" routerLinkActive="active">Contact</a></li>
</ul>
</nav>
</div>
<div [ngStyle]="getHeaderStyle()" class="app-mainheader">
<div class="app-mainheader__content set-margin">
this is the header for the
</div>
</div>
<router-outlet></router-outlet>
<app-footer></app-footer>
`,
styleUrls: ['./app.component.scss']
})
export class AppComponent {
showStyle = false;
getHeaderStyle() {
// ???
}
}
You could store the activateRoute as a member variable and style according to that.
export class AppComponent {
activatedRoute = "";
Then, when you click on a link, you set the activatedRoute.
<a routerLink="/" routerLinkActive="active" (click)="activateRoute('home')>
activateRoute(activatedRoute: string) {
this.activatedRoute = activatedRoute;
}
For the styling of the div, you use NgClass.
[ngClass]="{'home-class': activatedRoute === 'home', 'about-class': activatedRoute === 'about', ...}"
If you do not only want to do it, when someone clicks one of the links but always when the route is activated, then you should inject Router and check for the url.
[ngClass]="{'home-class': router.url === '/', 'about-class': router.url = 'about', ...}
// inject the router
constructor(public router: Router) {}
see a running example in this plunker
If you want to keep the style / conditional code out of the template in an a function, you can test the route value and return a class based on the current path. This is easy to read / maintain, although it may not be the most elegant solution:
import { Router } from '#angular/router';
constructor(
private router: Router
) {
}
getHeaderStyle() {
if (this.router.url.includes('/about/')
return 'red';
} else if (this.router.url.includes('/resources/')){
return 'green';
} else if (this.router.url.includes('/contact/')){
return 'yellow';
} else {
return 'blue'
}
In your component user [ngClass] to apply the class based on the function:
<div [ngClass]="getHeaderStyle()" class="app-mainheader">
<div class="app-mainheader__content set-margin">
this is the header for the
</div>
</div>
Then create your styles for each colour:
.red {
background-color: red;
}
etc.

Angular2 OverlayComponent not updating message variable

I have the below OverlayComponent that's serving as a processing spinner during async calls. The overlay pops up without issue but when I try and pass a message to it, the message doesn't stick.
Child Component
import {Component, OnInit} from '#angular/core';
import {OverlayComponent} from "../../shared/app.mysite.overlay.component";
#Component({
moduleId: module.id,
selector: 'tracker-component',
templateUrl: '/public/app/templates/pages/racker/mysite.tracker.component.html',
styleUrls: ['../../../scss/pages/tracker/tracker.css'],
providers: [OverlayComponent]
})
export class TrackerComponent implements OnInit{
constructor(private overlayComponent: OverlayComponent) {
}
ngOnInit(): void {
this.overlayComponent.showOverlay("Testing 123"); //<-- shows overlay but doesn't show the message in the overlay
}
}
Child Component HTML
<div id="TrackerContainer">
<div class="col-lg-12" class="container">
<div class="jumbotron jumbotron-header">
<div>
<div id="pageTitle">Tracker</div>
</div>
</div>
<div class="content-container container">
<div *ngFor="let item of tracker.activeMenu.items">
<card-component [item]="item"></card-component>
</div>
</div>
</div>
</div>
<overlay-component [message]="overlayMessage"></overlay-component>
OverlayComponent.ts
import { Component } from '#angular/core';
#Component({
selector: 'overlay-component',
templateUrl: '/public/app/templates/shared/mysite.overlay.component.html',
styleUrls: ['../../app/scss/shared/overlay.css']
})
export class OverlayComponent {
message: string;
//message: string = 'testing...'; <-- this updated the message just fine
showOverlay(msg: string) {
this.message = msg; // <-- the right value comes through in the msg variable but doesn't update in the page
$('.overlay-component-container').show();
}
hideOverlay() {
$('.overlay-component-container').hide();
this.message = '';
}
}
OverlayComponent.html
<div class="overlay-component-container">
<div class="overlay-component">
<div class="overlay-message">{{message}}</div>
<div>
<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>
</div>
</div>
</div>
The issue could be caused by a few things:
You don't need this here, this is just for services, not for components
providers: [OverlayComponent]
This isn't the way to get a reference to another component, you may not have the correct instance.
constructor(private overlayComponent: OverlayComponent)
Is <overlay-component> actually inside the HTML of the Tracker component?
Also where is the overlayMessage property on the tracker component? (as used below)
<overlay-component [message]="overlayMessage"></overlay-component>
Just ensure that the over-component is inside the tracker component, remove the this.message = msg; from showOverlay() and use two-way data binding to change the message.
I.E <overlay-component [message]="overlayMessage"></overlay-component>
If you add overlayMessage: string; to your Tracker component (or parent component of the overlay) Then all you need to do is update it in your parent component and your overlay component will pick up the changes.

Categories

Resources