Call function after signal value change

Discussão em 'Angular' iniciado por Pawel, Outubro 31, 2024.

  1. Pawel

    Pawel Guest

    I have a component with a simple login form.

    @Component({
    selector: 'app-login',
    standalone: true,
    imports: [
    ReactiveFormsModule,
    MatCardModule,
    ...
    ],
    templateUrl: './login.component.html',
    styleUrl: './login.component.scss',
    })
    export class LoginComponent implements OnInit {
    constructor(
    private route: ActivatedRoute,
    private router: Router,
    private formService: FormService,
    private appUserStore: AppUserStore,
    ) {
    this.isLoading = this.appUserStore.isLoading;

    effect(() => {
    if (this.appUserStore.isLogged()) {
    this.router.navigate([this.returnUrl]);
    }
    });
    }

    returnUrl = '/';
    isLoading = signal(false).asReadonly();

    loginForm: FormGroup<LoginForm> = new FormGroup<LoginForm>({
    login: new FormControl('', {
    validators: [Validators.required, Validators.minLength(2)],
    nonNullable: true,
    }),
    password: new FormControl('', {
    validators: [
    Validators.required,
    Validators.minLength(4),
    Validators.maxLength(50),
    ],
    nonNullable: true,
    }),
    });

    ngOnInit(): void {
    this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
    }

    onLogin() {
    this.appUserStore.login(this.loginForm.getRawValue());
    }

    }


    A simple user state store was prepared for authorization and storage of user state. The store was created based on NgRx SignalState, based on the documentation signal-state. My user state store is not complete yet.

    interface AppUserState {
    user: User;
    isLoading: boolean;
    isLogged: boolean;
    tokens: Tokens;
    }

    const initialState: AppUserState = {
    user: new User(),
    isLoading: false,
    isLogged: false,
    tokens: new Tokens('', '', 0),
    };

    @Injectable({
    providedIn: 'root',
    })
    export class AppUserStore {
    private readonly state = signalState<AppUserState>(initialState);
    private readonly authService = inject(AuthApiService);
    private readonly tokenCookieService = inject(TokenCookieService);

    readonly user = this.state.user;
    readonly isLogged = this.state.isLogged;
    readonly isLoading = this.state.isLoading;

    readonly login = rxMethod<LoginData>(
    pipe(
    tap(() => patchState(this.state, { isLoading: true })),
    exhaustMap((loginData: LoginData) => {
    return this.authService.login(loginData).pipe(
    tapResponse({
    next: (loginResponse) => {
    this.tokenCookieService.saveTokensCookie(loginResponse.tokens);
    patchState(this.state, {
    user: loginResponse.user,
    tokens: loginResponse.tokens,
    isLogged: loginResponse.user.id > 0,
    });
    },
    error: (error) => {
    this.resetState();
    console.log(error);
    },
    finalize: () => patchState(this.state, { isLoading: false }),
    }),
    );
    }),
    ),
    );

    private readonly resetState = () => {
    this.tokenCookieService.deleteTokensCookie();
    patchState(this.state, { ...initialState });
    };
    }



    Theoretically the component works as expected. After changing the login state, it redirects to the next url.

    My main question is whether "effect" used to detect a change in the user's login state is a correct solution.

    While searching for a solution on the Internet, I came across an opinion that "effect" should be used in specific cases. You should use "computed" to react to a change in the signal value, but I was unable to achieve the expected behavior of the component.

    I know that you can use "toObservable" from rxjs-interop to transform the signal to an observable, and then make a subscription. But is this a necessary and the only correct solution?

    Continue reading...

Compartilhe esta Página