I have a subscription to service:
login(): void {
if (!this.loginForm.valid) {
return;
}
const { email, password } = this.loginForm.value;
this.authService.login(email, password).subscribe((res) => {
if (res.ok) {
this.router.navigateByUrl('/dashboard');
} else {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: res.errorMessage,
});
}
});
}
This method is call when form is sumbited
<h1 class="mat-display-2 mb-0">Login</h1>
<form [formGroup]="loginForm" (submit)="login()">
<div class="form-group">
<mat-form-field class="form-field" appearance="standard">
<mat-label>Email</mat-label>
<label>
<input matInput formControlName="email" type="email" />
</label>
<mat-error *ngIf="controls.email.errors">
<span *ngIf="controls.email.errors.required">{{ 'auth.EMAIL_REQUIRED' | transloco }}</span>
<span *ngIf="controls.email.errors.email">{{ 'auth.INVALID_EMAIL' | transloco }}</span>
</mat-error>
</mat-form-field>
</div>
<div class="form-group">
<mat-form-field class="form-field" appearance="standard">
<mat-label>{{ 'auth.PWD' | transloco }}</mat-label>
<label>
<input matInput formControlName="password" type="password" />
</label>
<mat-error *ngIf="controls.password.invalid">{{ 'auth.PWD_REQUIRED' | transloco }}</mat-error>
</mat-form-field>
</div>
<p *transloco="let t">
{{ t('auth.LOGIN_HELP') }}
<a class="d-inline" routerLink="../signup" *transloco="let t">{{ t('auth.SIGNUP') }}</a>
</p>
<div class="text-right m-3">
<button mat-raised-button color="primary" class="mat-elevation-z8" type="submit" *transloco="let t">
{{ t('auth.LOGIN') }}
</button>
</div>
</form>
The problem comes when i change the language in interface because subscription to auth service is call with previous values of reactive form and for example if previous error was happened it fires again with the new language
¿How can i solve it?
I'm using transloco library for language
Complete login component
import { Component } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import Swal from 'sweetalert2';
import { AuthService } from '../../services/auth.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
})
export class LoginComponent {
loginForm: FormGroup = this.formBuilder.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required]],
});
constructor(private formBuilder: FormBuilder, private router: Router, private authService: AuthService) {}
get controls(): { [key: string]: AbstractControl } {
return this.loginForm.controls;
}
login(): void {
if (!this.loginForm.valid) {
return;
}
const { email, password } = this.loginForm.value;
this.authService.login(email, password).subscribe((res) => {
if (res.ok) {
this.router.navigateByUrl('/dashboard');
} else {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: res.errorMessage,
});
}
});
}
}
EDIT
I found a solution but is kind of weird...
login(): void {
if (!this.loginForm.valid) {
return;
}
const { email, password } = this.loginForm.value;
let subs: Subscription;
subs = this.authService.login(email, password).subscribe((res) => {
if (res.ok) {
this.router.navigateByUrl('/dashboard');
} else {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: res.errorMessage,
});
}
subs.unsubscribe();
});
}
I'm sure there's a better way of doing this (there are a lot of operators and use cases around RxJS), but as a valid solution/workaround the problem would get fixed if you just pick up the first emitted observable by using RxJS Operator "take", so you get rid of those repeated subscriptions coming next.
Example: On your AuthService call add a take(1):
this.authService
.login(email, password)
.pipe(take(1))
.subscribe(...)
Cheers.