Here are some pieces of code. This same pattern (afaik) works for the hero tutorial.
login.component.html:
<div class="four wide column middle aligned" *ngIf="wrongCredentialsInserted">
<div class="ui error message">Invalid credentials
</div>
</div>
login.component.ts:
wrongCredentialsInserted: boolean = false;
//...
onSubmit(login: LoginDto): void {
console.log(`User '${login.username}' attempts to login...`);
if (this.authService.login(login.username, login.password)) {
this.location.back();
} else {
this.wrongCredentialsInserted = true; //This line gets executed!
}
}
The message doesn't get displayed, even though I set wrongCredentialsInserted
to true. It gets set to true, I already validated that. I also tried things like *ngIf="wrongCredentialsInserted === true"
, because I read that somewhere else, but it didn't work.
I read that this could be related to "one way dataflow, starting with Angular 2", but I know that we were able to do such things in A2+ projects in our company. AFAIK one way databinding only refers to component-component communication.
Any kind of help is highly appreciated.
EDIT: Since there seems to be a bit of confusion with the things I did, I post the whole files here.
login.component.ts
import {AbstractControl, FormBuilder, FormControl, FormGroup, Validators} from '@angular/forms';
import {routerTransition} from '../../router.transition';
import {Component} from '@angular/core';
import {AuthService} from '../auth.service';
import {LoginDto} from './login-dto';
import {Location} from '@angular/common';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
animations: [routerTransition()]
})
export class LoginComponent {
private readonly USERNAME: string = 'username';
private readonly PASSWORD: string = 'password';
myForm: FormGroup;
username: AbstractControl;
password: AbstractControl;
message: string;
wrongCredentialsInserted = false;
constructor(public fb: FormBuilder,
public authService: AuthService,
public location: Location) {
this.message = '';
this.myForm = fb.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
this.username = this.myForm.controls[this.USERNAME];
this.password = this.myForm.controls[this.PASSWORD];
}
onSubmit(login: LoginDto): void {
console.log(`User '${login.username}' attempts to login...`);
if (this.authService.login(login.username, login.password)) {
this.location.back();
} else {
this.wrongCredentialsInserted = true;
}
}
login(username: string, password: string): boolean {
this.message = '';
if (!this.authService.login(username, password)) {
this.message = 'Incorrect credentials.';
setTimeout(
function () {
this.message = '';
}.bind(this), 2500);
}
return false;
}
logout(): boolean {
this.authService.logout();
return false;
}
}
login.component.html
<div class="ui raised segment">
<form [formGroup]="myForm"
(ngSubmit)="onSubmit(myForm.value)"
class="ui form"
[class.error]="!myForm.valid">
<div class="field"
[class.error]="!username.valid && username.touched">
<label for="username">Username:</label>
<input type="text"
id="username"
placeholder="Username"
[formControl]="username">
<div *ngIf="username.hasError('required') && username.touched"
class="ui error message">
Username is required
</div>
</div>
<div class="field"
[class.error]="!password.valid && username.touched">
<label for="password">Password:</label>
<input type="text"
id="password"
placeholder="Password"
[formControl]="password">
<div *ngIf="password.hasError('required') && password.touched"
class="ui error message">Password is required
</div>
</div>
<div class="ui grid">
<div class="two wide column middle aligned">
<button type="submit"
class="ui button"
[class.disabled]="!myForm.valid">Submit
</button>
</div>
<div class="fourteen wide column middle aligned" *ngIf="wrongCredentialsInserted">
<div
class="ui error message">Invalid credentials
</div>
</div>
</div>
</form>
</div>
login.component.css: Empty
auth.service.ts:
@Injectable()
export class AuthService {
constructor(private http: Http) {
}
login(user: string, password: string): boolean {
if (user === 'user' && password === 'password') {
localStorage.setItem('username', user);
return true;
}
return false;
}
logout(): any {
localStorage.removeItem('username');
}
getUser(): any {
return localStorage.getItem('username');
}
isLoggedIn(): boolean {
console.log(`Is user logged in? ' + ${this.getUser() !== null}`);
return this.getUser() !== null;
}
}
The *ngIf directive is most commonly used to conditionally show an inline template, as seen in the following example. The default else template is blank.
The * syntax means that ngIf is a structural directive, meaning that it affects the structure of the page.
The ngIf Directive in Angular10 is used to remove or recreate a portion of HTML element based on an expression. If the expression inside it is false then the element is removed and if it is true then the element is added to the DOM.
Both are the same in terms of performance, becouse both are angular common atributes (*ngIf === [ngIf]) and they work equal at angular rendering. Save this answer.
There are a couple of possible reasons for *ngIf
not reacting to change in the model.
You're using OnPush
strategy on your component and changing the component state without manually triggering a CD cycle. Either turn back on automatic CD or trigger the CD manually by injecting the ChangeDetectorRef
and using the method which suits your needs.
It's possible that ngIf
binding is working correctly and that the template is properly created and destroyed, but there are styles which visually obscure this, such as display: none
, visibility: hidden
, etc. Make sure to inspect the page by opening your browser's dev tools.
Easy to miss if you do not have your console open while developing. There might've been an error which has broken your code and Angular cannot recover from it; thus preventing any further CD cycles to run and update the DOM. Be sure to have an open console to check for errors.
Angular is a framework where you declaratively specify how you want the DOM to be created based on the model. You do this by writing templates. If your model does not change, the DOM won't either. Make sure that the correct piece of code is running. A quick way to do this is by placing a console.log
near the code that changes the variable. You can also place a breakpoint in your browser's dev tools, or use a utility extension for Chrome such as Augury to inspect the model independently from the way it's rendered based on the template.
I had similar issue earlier with *ngIf not reating to change in value, but it was because my boolean was being sent as string from backend eg: "true"
or "false"
and the solution that I found worth was
yourVariable = booleanValue === "true" ? true : false
Hope this Helps.
In my case this issue happened because the change was happening outside of Angular's zone. Running the code inside change detection cycles fix the issue. Few options you have in this case are
Wrap the third party function inside a zone.run (Inject NgZone to the controller)
myFunctionRunByAThirdPartyCode(){
this.ngZone.run(this.myFunction);
}
Wrap the function inside a setTimeout
myFunctionRunByAThirdPartyCode(){
setTimeout(this.myFunction,0);
}
Call detectChanges() manually (Inject ChangeDetectorRef to the controller)
myFunctionRunByAThirdPartyCode(){
this.changeDetectorRef.detectChanges();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With