admin管理员组

文章数量:1123692

I have a component with 2 input signals that have no value initially. I need to send http request only one time and it should be the moment both signals have value.

What is the proper way to do it? Should I use effect that I manually destroy after first execution or is there some other way?

I have a component with 2 input signals that have no value initially. I need to send http request only one time and it should be the moment both signals have value.

What is the proper way to do it? Should I use effect that I manually destroy after first execution or is there some other way?

Share Improve this question asked yesterday tlttlt 15.1k11 gold badges51 silver badges91 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 1

Really it's the reason to use signals and effect. Just check if have value the two inputs:

export class MyComponent {
  value1 = input<any>(null);
  value2 = input<any>(null);

  constructor() {
    effect(() => {
      const value1=this.value1()
      const value2=this.value2()
      if (value1 && value2)
         ..do something..
    });
  }
}

A stackblitz

This is my version, which uses rxResource to cache the value once a certain condition is met, we can use cached property to store the cached value and return it, when it is being set (the condition that sets this property is when both the signals have a value).

First we initialize a rxResource to make the API call, we use two signals (signal1 and signal2) (I am using modal instead of input here), Using this, we can make the API setup.

Then we can use a simple if condition to cache the value when our condition is met.

  cached!: any[];
  resource: ResourceRef<any[]> = rxResource({
    request: () => ({
      signal1: this.signal1(),
      signal2: this.signal2(),
    }),
    loader: ({ request: { signal1, signal2 } }) => {
      if (this.cached) {
        return of(this.cached);
      }
      if (signal1 && signal2) {
        // simulate API
        return of([{ dataReceved: true }]).pipe(
          tap((res: any) => {
            this.cached = res;
          })
        );
      }
      return EMPTY;
    },
  });

Full Code:

import {
  Component,
  effect,
  linkedSignal,
  model,
  ResourceRef,
  ResourceStatus, 
  WritableSignal,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { CommonModule } from '@angular/common';
import { rxResource } from '@angular/core/rxjs-interop';
import { of, EMPTY, tap } from 'rxjs';
import { FormsModule } from '@angular/forms';
@Component({
  selector: 'app-root',
  imports: [CommonModule, FormsModule],
  template: `
    {{ resource.value() | json }}
    <input [(ngModel)]="signal1" />
    <input [(ngModel)]="signal2" />
  `,
})
export class App {
  signal1 = model(null);
  signal2 = model(null);
  cached!: any[];
  resource: ResourceRef<any[]> = rxResource({
    request: () => ({
      signal1: this.signal1(),
      signal2: this.signal2(),
    }),
    loader: ({ request: { signal1, signal2 } }) => {
      if (this.cached) {
        return of(this.cached);
      }
      if (signal1 && signal2) {
        // simulate API
        return of([{ dataReceved: true }]).pipe(
          tap((res: any) => {
            this.cached = res;
          })
        );
      }
      return EMPTY;
    },
  });
}

bootstrapApplication(App);

Stackblitz Demo

To trigger an HTTP request when both input signals have values in Angular, you can use the combineLatest operator from RxJS. This approach ensures the request is sent only once, as soon as both signals are non-null, and it automatically unsubscribes after the first emission.

Example Code:

Below is a complete implementation of the solution:

import { Component, Input, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Signal } from '@angular/core';
import { combineLatest, filter, take } from 'rxjs';

@Component({
  selector: 'app-my-component',
  template: `<!-- Your template here -->`,
})
export class MyComponent implements OnInit {
  @Input() signal1!: Signal<any>;
  @Input() signal2!: Signal<any>;

  constructor(private http: HttpClient) {}

  ngOnInit() {
    combineLatest([this.signal1, this.signal2])
      .pipe(
        filter(([value1, value2]) => value1 != null && value2 != null), // Ensure both have values
        take(1) // Automatically unsubscribe after the first emission
      )
      .subscribe(([value1, value2]) => {
        // Send your HTTP request here
        this.http.post('https://example.com/api', { value1, value2 }).subscribe(
          response => {
            console.log('HTTP request successful:', response);
          },
          error => {
            console.error('HTTP request failed:', error);
          }
        );
      });
  }
}

本文标签: angularHow to run function just one time when 2 signals have valueStack Overflow