Change the buttons on the angular material Nav-bar based on page - html

I have my navbar deigned using angular material in my app.component.html page.
It initially contains LOGIN button, but when user is logged in successfully, login button should be hidden
Current approach:
I am disabling the login button based on boolean attribute in localstorage, but in this case, login button is not disabled until i refresh my page.
My Navbar is created as shared component, So Is there a way i can add new button based on page and data is updated without refreshing the page?
app.component.html:
<app-navbar></app-navbar>
<router-outlet></router-outlet>
Navbar.component.html:
<mat-toolbar color="primary" class="mat-elevation-z">
<span><mat-icon>post_add</mat-icon> ED-Planner</span>
<div class="spacer"> </div>
<button mat-button [routerLink]="['/user']">Home</button>
<button mat-raised-button color="accent" [routerLink]="['/user/signup']">Signup</button>
</mat-toolbar>
Any help would be appreciated

Well, user data usually is stored in localstorage.
If you create a service for example, you can store it there too, and provide it (make sure its providedIn root, so there will be only 1 instance).
After you log in your user, you can store it's data in the service, or localstorage (please pay attention for security), you can do something like this:
<ng-container *ngIf=isLoggedIn; else loggedOut>
//Your content when the user is logged in), few else buttons for example profile or something
</ng-container>
<ng-template #loggedOut>
//your login section
</ng-template>

Related

Angular - two the same ng-template with component in one HTML file (How to make reference, not copy)

I have the following problem: I create a web application using Angular. I am making a search form that has several fields. I have it ready as a component. Code below:
<ng-template #filter>
<app-articles-filter #articlesFilterDesktop
(onFilterFormSubmit)="submitFilterForm()"
[categories]="categories"></app-articles-filter>
</ng-template>
To put this code on the page, I'm using ng-container: <ng-container *ngTemplateOutlet = "filter"> </ng-container>. By default, the search form is at the top of the page. I also wanted to do so that when the user resize the window (mobile devices), a button will appear in the place of the search form. After clicking on this button a modal window with this search form would appear. Modal window code (I'm using Bootstrap):
<div class="modal fade" id="filterArticlesModal" tabindex="-1" role="dialog" aria-labelledby="filterArticlesModalTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<ng-container *ngTemplateOutlet="filter"></ng-container>
</div>
</div>
</div>
</div>
Having the same component twice with ng-template in one HTML file, I get a warning in the console:
"Found 2 elements with non-unique id [duplicated id here]: [html from search form here]".
The fields completed in the search form are not automatically completed in the modal view. (When I complete the form on the page, narrow the browser window and open the modal window.. there are empty fields in the modal window and vice versa). As I understand it, Angular just pastes the code and that's it. Is it possible to somehow treat this code fragment (my search form component) as one reference and not a copy?
EDIT:
I'm not sure about the duplicate ID fiasco. You could remove id's and just go off of classes, or maybe have some property from the component added in to the ID that you can control: id="searchBar{{foo}}"?
Solving the data consistency when you switch between searches can definitely be done.
If you want to have the search value act as a singleton I recommend putting that value in a service, and referencing it from the components. This can be done a few different ways, and there is one thing to consider:
Do you want the search to persist after the page in navigated to/from? If yes then keep the service that stores the search global, if not define it in the providers: [] property of the component that houses these search components (that way it gets deleted each time the component is destroyed)

Embedded view not showing when switching between views using ngIf

My component A has a child component B. On start up, A shows up because of conditition in *ngIf. A uses an EmbeddedView show show image thumbnails. A also has a button which when clicked changes the condition of *ngIf and shows B (because B shows on some other condition of *ngIf). If a button in B is pressed then A shows back again.
A's html is something like
<div *ngIf="this.tabType == this.questionTab" id="form-div-question" class="body__div--background">
....
<ng-template #thumbnailTemplate let-context="context">
<div id="{{context.divId}}">
<button id="{{context.buttonId}}" type="button" data-toggle="modal" (click)="showEnlargeImage(context)">
<img id="{{context.imgId}}" src="{{context.imgSrc}}"/>
</button>
<a *ngIf="this.isEditing" href="javascript:void(0)" id="{{context.closeId}}" (click)="deleteThumbnailFromContainer(context)"></a>
</div>
</ng-template>
...
<div id="image-thumbnail-container">
<ng-container #thumbnailContainer ></ng-container>
</div>
</div>
<div *ngIf="this.tabType == this.submittedAnswerTab" id="form-div-submitted-answer" class="body__div--background">
<b-component #bComponent [someInput]="..." (someEventFromB)="switchToQuestionTab($event)"></b-component>
</div>
The EmbeddedView in A is access as follows
#ViewChild("thumbnailContainer",{read:ViewContainerRef})
thumbnailContainerRef:ViewContainerRef;
What I am noticing is that on start up A shows fine including its embedded view. Then B also shows when the button in A is clicked. But when the view switches back to A then the embedded view doesn't show up!! (rest of A shows up correctly). I tried to force recreating the embedded view, I get error that the reference to the container is not defined (i.e.thumbnailContainerRef is undefined).
I also notice that when B is shown, it seem to be initiated everytime but when A is shown, it is not reinitialised everytime (maybe because B is child and A is parent)
Why is the container reference becoming undefined?
Taking inspiration from Angular 2 Show and Hide an element and What is the difference between *ngIf and [hidden]?
I seem to have solved the problem by using [hidden] instead of ngIf of A component.
<div [hidden]= "this.tabType != this.questionTab" ...>
</div>
<div *ngIf="this.tabType == this.submittedAnswerTab" id="form-div-submitted-answer" class="body__div--background">
<b-component #bComponent [someInput]="..." (someEventFromB)="switchToQuestionTab($event)"></b-component>
</div>
It seems that when '*ngIf' is false for A, Angular removes the embedded view and it doesn't get created again which seem to to be the reason why the ViewContainerRef is undefined when I switch back to A. Using [hidden] just hides A. Maybe there is code smell in my implementation but hey, I am still learning!

How to hide Login and Register link to other pages in Angular

In App.component.ts I have redirected the router link to home, where I want to hide Login and Register link. I know lot of people will answer authGuard, I am new to angular. Just want to know how to hide some link or feature on diferent diferent pages on router base I think I can do it in ngIf and router link but where to write. Flow is after clicking on login or register want to hide the link
Can anyone please help?
<a [routerLink]="['/login']" class="btn btn-link">Login</a>
<a [routerLink]="['/registration']" class="btn btn-link">Register</a>
<router-outlet></router-outlet>
You need a logged in flag on a shared service.
Create a serviceCalled LoggedIn
#Injectable({
providedIn: 'root'
})
export class LoggedInService {
loggedIn$ = new BehaviorSubject(false);
}
Inject the service where you log in and call next on the BehaviorSubject when you log in
this.loggedInService.loggedIn$.next(true);
and on the component with the menu use it to hide the login button
loggedIn$ = this.loggedInService.loggedIn$;
and in the template
<a [routerLink]="['/login']" class="btn btn-link" *ngIf="loggedIn$ | async">Login</a>

Angular 6 - how to go to another view by clicking the icon?

i dont have the idea how to do it. please can you give me an idea on how to go to another view by clicking the icon on the Angular6? Thank you!
To change view in Angular(without reloading page), you need Routers.
You can wrap your icon inside an anchor tag <a> and use routerLink to define the view you want to load when a user clicks on the icon.
For example, you are building an e-commerce site where you have an icon for contacts and one for a shopping cart. You can define view for each icon like this:
<a routerLink="/contacts" routerLinkActive="active">
<mat-icon matSuffix>contacts</mat-icon>
</a>
<a routerLink="/shopping_cart" routerLinkActive="active">
<mat-icon matSuffix>shopping_cart</mat-icon>
</a>
So when the user clicks on contacts icon, contactsComponent will be loaded in your view and the URL would change to yourwebsite.com/contacts.
You can learn more about routers and material-icon.

How to open/close a angular-material menu

I recently started using angular-material and am struggling/unsure about opening/closing a mat-menu... I see in the examples on the angular-material documentation site that they assign an id to the menu and then apply a directive to the button that is used to toggle the menu. e.g. [matMenuTriggerFor]="menu"
How can I go about writing a directive that does that? I'm not sure how to pass a reference to a specific menu to a directive that then calls the toggle() method on the DOM element with that id?
The following code produces the errors:
Can't bind to 'matMenuTriggerFor' since it isn't a known property of 'button'.
There is no directive with "exportAs" set to "matMenu".
My code:
<li>
<button mat-icon-button [matMenuTriggerFor]="stockSystemMenu">
<mat-icon class="sn-item">
<i class="material-icons">archive</i>
</mat-icon>
</button>
<span class="sn-item" (click)="toggleMenu(stockSystemMenu)">Stok System</span>
<mat-menu #stockSystemMenu="matMenu">
<button mat-menu-item>
<mat-icon>
<i class="material-icons">chevron_right</i>
</mat-icon>
<span>Service 1</span>
</button>
</mat-menu>
</li>
There is confusion because Material introduced a breaking change as I understand it.. See material 2 Changelog - Breaking Changes
Starting with Material 2.0.0-beta.12. Use mat instead of md-*.. Seems only some of the docs at material.angular.io are updated with mat. Specifically, if you click view source and see md, I believe they have yet to replace it with mat.
So either update to Material 2.0.0-beta.12 and use mat-*, or use md-*.
"Your code is correct, you don't need to write matMenuTriggerFor directive, it is part of the API, make sure you have imported the MatMenuModule, MatButtonModule, and MatIconModule into your app module." - from comments