Changing values of a counter variable in Angular - html

I have 2 buttons on my login page, Button1 and Button2. Both the buttons direct to the same URL page. But on clicking Button 2, I want to disable the functionality of Button 3 which is on the next URL page.
Button 3 should be accessed only when Button 1 was clicked on the main page.
Here's the HTML code of the main page. Button 1 is a part of the ngForm.
<button class="btn btn-primary" id="alert" type="submit">Login</button>
<button class="btn-primary" routerLink="/login/olduser" id="logins">Patient Login</button>
Here's the HTML code of Second page.
<button class="btn btn-primary" style ='margin-left: 700px;'routerLink="../../login/newuser">Register a new patient </button>
One possible solution I thought of was exporting a counter variable from the main page to the second page on clicking Button 2, which will inform to disable Button 3, but I failed to do so.
How can I implement this functionality?
Here's what I have tried till now :
<button class="btn-primary" (Click)="newUser()" id="logins">Patient Login</button>
public newUser(){
var status="success";
console.log(status);
this.router.navigateByUrl('/login/olduser');
}
I'm trying to print the value of "status" on console, to check if the method is being accessed but there's no output on console and also the url doesn't change.
I want to call this "status" variable in olduser.ts script.

It seems you're trying to limit the functionality of some sort of dashboard depending on user type (patient, non-patient).
I don't think you should rely on a referrer button at all here.
I'd send something like a list of permissions for user to client app after logging in and wrap it in a AuthorizationService of some kind. Then I'd check if the user has the permission to register a new patient and show/hide the corresponding button.
Of course, you shouldn't forget about server-side validation for registration requests.
UPD: if one of the user types doesn't distinguish between users and doesn't require server-side authentication, you can just generate some kind of default set of permissions in the service for those non-privileged users and keep the display logic for page 2 based on permission checks.

On Click of button pass a query parameter. Then on the next page read the value of the query parameter from URL and disable the button 3 based on the value.
Working Demo
Homepage HTML
<a routerLink='/page1' [queryParams]="{button: 'a'}"><button>button 1</button></a>
<a routerLink='/page1' [queryParams]="{button: 'b'}"><button>button 2 </button></a>
<router-outlet></router-outlet>
In the routed component .TS
import { Component, Input, OnInit } from "#angular/core";
import { ActivatedRoute } from "#angular/router";
#Component({
selector: "hello",
template: `
<h1>Hello {{ name }}!</h1>
<button [disabled]="isDisable">button3</button>
`,
styles: [
`
h1 {
font-family: Lato;
}
`
]
})
export class HelloComponent implements OnInit {
#Input() name: string;
isDisable: boolean;
constructor(private activatedRoute: ActivatedRoute) {}
ngOnInit() {
this.activatedRoute.queryParams.subscribe(params => {
this.isDisable = params.button === "a";
});
}
}

You can send the state of the button as a query parameter on button 2 click. Now, On the new page get the query params value and then apply property binding.
On Button 2 click :
this.router.navigate(['/newpage'], { queryParams: { state: "false"});
Now, on new page add as below :
import { ActivatedRoute } from '#angular/router'
export class newPage implements OnInit {
btnState
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.route.queryParams
.filter(params => params.state)
.subscribe(params => {
this.btnState = params
});
}
Now,apply property binding to the button
<button [disabled]="btnState">Button3</button>

There is multiple ways to achieve what you try to do:
With the click on Button 2, you can store in a service, a variable isActive to false and in your next url/Component, check from the service the variable to disabled or not your Button 3.
Navigate to your url with a params: my-new-url?ACTIVE=false, and in your new url/component, check the url to find the Params and disable your button according to the value

Related

Router navigation & modal close

I'm using a form component within 2 separate components in an Angular project. When the user selects 'Save' I would like my onSubmit function to close a modal if it's in one of the components or use the router link if it's in another.
I currently have my onSubmit function to finish with the router link as shown below:
async onSubmit() {
this.router.navigate(['/home']);
}
But I would also like this to include closing a modal and not navigating when the user is in a different component.
<div class="modal-body">
<app-add-form></app-drug-audit-add-form>
</div>
I used a form handler and linked this to the function.
HTML
<app-add-form (saveFormHandler)="onSave()"></app-add-form>
TS (first file)
#Output()
saveFormHandler = new EventEmitter();
onSubmit() {
this.saveFormHandler.emit();
this.saveFormHandler2.emit();
}
TS (second file)
onSave() {
this.router.navigate(['/drug-audit']);
}
TS (third file)
onSave() {
this.modalRef.hide();
}

'trim' of undefined TypeError in Angular app when I don't call trim anywhere

I'm currently trying to learn Angular and as I'm working through a couple of ideas I had, I ran into the following error in the dev console of Chrome:
ERROR TypeError: Cannot read property 'trim' of undefined
at Function.addMultipleClasses (primeng-dom.js:19)
at ButtonDirective.createIconEl (primeng-button.js:59)
at ButtonDirective.setIconClass (primeng-button.js:78)
at ButtonDirective.set label [as label] (primeng-button.js:92)
at setInputsForProperty (core.js:10940)
at elementPropertyInternal (core.js:9984)
at ɵɵpropertyInterpolate1 (core.js:15551)
at Module.ɵɵpropertyInterpolate (core.js:15514)
at CmsComponent_Template (cms.component.html:12)
at executeTemplate (core.js:9579)
Here is my HTML:
<h1>Angular Router App</h1>
<!-- This nav gives you links to click, which tells the router which route to use (defined in the routes constant in AppRoutingModule) -->
<nav>
<ul>
<li><a routerLink="/login" routerLinkActive="active">/login</a></li>
<li><a routerLink="/" routerLinkActive="active">/</a></li>
</ul>
</nav>
<button type="button"
pButton
label="{{word}}"
(click)="buttonPress()">
</button>
<!-- The routed views render in the <router-outlet>-->
<router-outlet></router-outlet>
And here is my TS:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-landing',
templateUrl: './cms.component.html',
styleUrls: ['./cms.component.scss']
})
export class CmsComponent implements OnInit {
private onWord: number = 0;
private words: Array<string> = ["One","Two","Three","Two"];
public word: string = this.words[this.onWord];
constructor(
) { }
ngOnInit(): void {
}
public buttonPress(): void {
// Bumps the index
this.onWord++;
// Keeps the value in the proper range
if (this.onWord >= this.words.length) {
this.onWord = 0;
}
// Updates the word to the new index
this.word = this.words[this.onWord];
console.log("The button is now on " + this.word);
}
}
I'm using Angular and Typescript. Any thoughts on what's going wrong? The button functions as intended except for that error whenever I click it.
Thanks!
was the same problem, I found a solution on the official forum, in order to fix the error you need to add -> icon = "pi"
<button
icon="pi"
type="button"
pButton
[label]="(documentsCount$ | async)?.toString()"
></button>
This is not an error generated from your code but in the package you're using (in this case PrimeNg). The method seems to be expecting some input which it's not getting. Try passing '$event' in the click method and handle it in the ts file.
(click)="buttonPress($event)"
As an ideal implementation, use the predefined button element provided by PrimeNg.
Turns out having {{word}} as the button label broke things!
Apparently I can't have dynamically changing button labels...
Use p-button instead:
<p-button
label="{{word}}"
(onClick)="buttonPress()">
</p-button>
See the forum entry

Angular show fetched data after click dropdown button

I use angular at the frontend and .net core at the backend. I have a trivial problem and figure it with a video below. I spend hours and hours and still couldn't solve the problem.
I simply fetch data from my web api. And use *ngFor for display the data. But the problem is data is not shown before click any dropdown button.
Btw, dropdown button does not have any click event. It's simple language selector.
When I click language selector dropdown button, it expands and at the same time my data display on the screen.
I get my data ngOnInit. I check the data on debug mode and it's ok. I really spend hours and hours...still couldn't find any solution.
My html code :
<div class="container">
<div *ngFor="let d of devices"> --> I put here breakpoint and it run when I click dropdown btn
<span>{{d.name}}</span>
</div>
</div>
My .ts code:
import { ChangeDetectorRef, Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { ToastrService } from 'ngx-toastr';
import { Observable } from 'rxjs';
import { Pagination } from '../../../_helpers/Pagination';
import { deviceListModel, NewDeviceModel } from '../../admin-panel.model';
import { AdminPanelService } from '../../admin-panel.service';
#Component({
selector: 'app-test',
templateUrl: './test.component.html',
styleUrls: ['./test.component.scss']
})
export class TestComponent implements OnInit {
devices : Array<deviceListModel>; ---> I also try with public deviceList : deviceListModel[]; nothing change
constructor(private service : PanelService, private router : Router) { }
ngOnInit(): void {
this.getDeviceList();
}
getDeviceList() {
this.service.getDeviceList().subscribe(res => {
this.devices = res;
})
} ---> This part works fine. Data comes true from the backend before click the dropdown button.(I checked in debug mode with breakpoints)
}
Visiulize my problem with below link;
https://media.giphy.com/media/jYGHN1Ndxyeqhtn0ZR/giphy.gif
fullscreen with low res : https://giphy.com/gifs/jYGHN1Ndxyeqhtn0ZR/fullscreen
Edit :
When I try just display one of the data like devices[0].name;
<div>
<span> {{devices[0}.name}} </span>
</div>
I get data on page but with an error in console.
The error comes three times and the error is ;
core.js:4352 ERROR TypeError: Cannot read property '0' of undefined
Try putting the this.devices = res; into the NgZone
constructor(..., private _ngZone: NgZone)
this._ngZone.run(() => { this.devices = res; });
Can you try to put an *ngIf in the container? Like so:
<div class="container" *ngIf="devices?.length">
<div *ngFor="let d of devices">
<span>{{d.name}}</span>
</div>
</div>
In this case, the template will only be rendered when the backend call has completed successfully (and has results).

Link takes double click to activate- how to make it only one? Angular 5

I'm building an app in Angular 5 and have a navigation component that will display various tabs/links. When the link is active (currently being viewed) the tab will have a border around it and look like it is the front of a file folder.
The problem is, I only need to click once in order to make the link appear active, but have to click the tab/text twice in order to get it to actually load the page. Why is that, and how can I get it to load completely after one click? Does this happen because I have two click events activated on one link?
My tabs in html:
<div *ngIf="authService.current_route == '/' ">
<a [routerLink]="['']" data-toggle="tab">
<li [class.active-link]="selectedTab === 0" (click)="changeroute()" (click)="selectTab(0)" >Site List</li>
</a>
<a [routerLink]="['/sites/map']" data-toggle="tab">
<li [class.active-link]="selectedTab === 1" (click)="changeroute()" (click)="selectTab(1)" >All Sites Map</li>
</a>
<a [routerLink]="['/user-access']" data-toggle="tab">
<li [class.active-link]="selectedTab === 2" (click)="changeroute()" (click)="selectTab(2)" >User Access</li>
</a>
</div>
In my component:
export class NavigationComponent implements OnInit {
deciding_route: any;
selectedTab = 0;
current_site;
local_route
current_site_id
selectTab(tabId: number) {
this.selectedTab = tabId;
}
constructor(public authService: AuthService, private router: Router, private route: ActivatedRoute) { }
ngOnInit() {
}
changeroute() {
this.authService.current_route = this.router.url;
this.authService.route_with_id = this.authService.current_route
}
}
Thanks so much!! Let me know if I can clarify anything.
The problem might seem to be related with the fact that the click will trigger before the router actually change the route, then, calling your method changeroute(); doesn't change anything because the route is still the same at this time; however, when you click the second time, the route have already been changed, after the first click handler, so it changes according to the expected route.
A way out is to transfer the changeroute() method to a route change listener:
constructor(private router: Router) {
router.changes.subscribe((val) => { this.changeroute(); })
}
You could also move the click handler upwards, i.e, move to an element which would be parent of the routerLink so that your click would happen after the click on the link, it might work as well.
Further explanation
Consider the following component:
#Component({
selector: 'my-test',
template: `
<div (click)="onClick1()">
<button (click)="onClick2()">Click</button>
</div>`,
})
export class TestComponent {
onClick1(){
console.log('click 1')
}
onClick2(){
console.log('click 2')
}
}
If the button gets clicked, it is going to display the console like bellow:
click 2
click 1
It implies the propagation starts on the child (tip) to parents until reach the root node (provided that your would have listener for all parents until the root).
In my case there was an error in the component I was navigating from but no error in the console because navigate is a promise.
After consuming the promise I found the issue it the error written to the console.
const nav = this.router.navigate(['myapp/dashboard']);
nav
.then((v) => {
console.debug('to dashboard', v);
})
.catch((e) => {
console.error('to dashboard', e);
});

How can I change component without changing URL in Angular?

I would like to change component without changing URL. Let's assume that I have a component register. When I open my website I have url www.myweb.com. Then I would like to register by clicking sign up. I would like to display my component register without changing URL. Should I use ngIf or something else? Can you show me example how it should be done?
UPDATE I am sorry, but it seems to me that I was misunderstood. I tried
this solution:
login.component.ts:
showSignUp: boolean = false;
login.component.html:
<button (click)="showSignUp = true">Sign Up</button>
<register *ngIf="showSignUp"></register>
However when I clicking the button Log in I get this:
before:
after clicking:
After clicking the button Log in I would like to get a new website but with the same URL like this:
UPDATE
What do you think about solution shown below? In html file I will be checking whether variable authenticated is equal true. If so then I will display home component.
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.authenticated = true;
// this.router.navigate([this.returnUrl]);
},
error => {
this.authenticated = false;
this.alertService.error(error);
this.loading = false;
});
}
UPDATE
Unfortunately it doesn't work. Any ideas how can I use it with this button?
<button [disabled]="loading" class="btn btn-primary">Log in</button>
You can use *ngIf and show the component in condition!
examle
In your sign up component, set a variable and change its value on click of sign up button. And display your register component on click of the login by pitting the condition in display
// sign up component
showRegister = false;
in your sign up component html
<register *ngIf="showRegister"></register>
Yes, this is a perfect use case for ngIf. Try not to over engineer it.
ngIf is the way to go on this kind of thing.
Just put in your component code something like
showSignUp: boolean = false;
then in template:
<button (click)="showSignUp = true">Sign Up</button>
<register *ngIf="showSignUp"></register>
And since you seem new to Angular, I'll mention that in order to use ngIf in template, your module needs to import the CommonModule like
import { CommonModule } from '#angular/common';
imports: [
CommonModule,
]