Search code examples
angularrxjsrxjs6rxjs-observables

Rxjs Subject not emitting data immediately


I have a service with a RXJS subject and i am assigning data to subject inside constructor doing an api call. This subject I am subscribing in a component template. Though the data is provided to the subject, it is not emitting immediately the first time.

interface Employee {
  employee_age: number;
  employee_name: string;
  employee_salary: number;
  id: string;
  profile_image: string;
}

@Injectable({
  providedIn: "root",
})
export class EmployeeService {
  employeesSub = new Subject<Employee[]>();

  employees: Employee[];

  constructor(private http: HttpClient) {
    this.api().subscribe((res) => {
      this.employees = res.data;
      this.employeesSub.next(this.employees);
    });
  }

  getEmployees(){
    this.employeesSub.next(this.employees);
  }

  addEmployee(name,age,salary) {
    this.employees.unshift({
      id:(this.employees.length + 1).toString(),
      employee_age: age,
      employee_name: name,
      employee_salary: salary,
      profile_image: ""
    });
    this.employeesSub.next(this.employees);
  }

  api() {
    return this.http
      .get<any>(environment.employeeUrl)
      .pipe(map((data) => data.items));
  }
}

Code in template

<h2>List</h2>

<div style="display: flex;"></div>

<table>
  <tr *ngFor="let item of employeeService.employeesSub | async">
    <td>{{ item.employee_name}}</td>
    <td>{{ item.employee_age}}</td>
    <td>{{ item.employee_salary}}</td>
  </tr>
</table>

I am reassigning data by calling the getEmployees() function after 200ms and it is working. Any idea why this is happening.


Solution

  • You need to switch to a BehaviorSubject.

    The service gets initialized before the component does, so it's emitting the value before the component gets to subscribe. Since a Subject doesn't hold a value, the component doesn't get anything. By swapping to a Behavior subject, you can subscribe to it and immediately get the latest value.

    The accepted answer here describes the difference been a Subject and a BehaviorSubject well.

    // Init the subject with a starting value, to be updated in the constructor later
    employeesSub = new BehaviorSubject<Employee[]>([]);
    
    constructor(private http: HttpClient) {
        this.api().subscribe((res) => {
            this.employees = res.data;
            this.employeesSub.next(this.employees);
        });
    }