Search code examples
angulartypescriptsignalsangular16

Call component method when service's signal updates


Let me preface this question with the fact that I started learning Angular about a month ago.

Basically, I have a searchbar component and several different itemcontainer components (each of them displays a different type of item). In an attempt to have access to the serchbar value on any component, I created a searchbarService like so:

import { Injectable, signal, WritableSignal } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class SearchBarService {

  searchTextSignal: WritableSignal<string> = signal('');

  setSearch(text: string): void{
    this.searchTextSignal.set(text);
  }
}

The searchbar component calls the setSearch method on input submit. So far so good. Now, the problem comes when trying to work with searchTextSignal on the itemcontainter components. I'm trying to use it like this:

import { Component, signal} from '@angular/core';
import { Factura } from 'src/app/interfaces/factura';
import { FacturaService } from 'src/app/services/factura.service'; //gets items from a placeholder array.
import { SearchBarService } from 'src/app/services/search-bar.service';

@Component({
  selector: 'vista-facturas',
  templateUrl: './vista-facturas.component.html',
  styleUrls: ['./vista-facturas.component.css']
})
export class VistaFacturasComponent {

    facturasArray: Factura[] = []; // has all items
    filteredFacturasArray = signal<Factura[]>([]); // has all filtered items, and is the value that I want to get updated when the signal changes.

    constructor(private facturaService: FacturaService, public searchBarService: SearchBarService) { }

    getFacturas(): void { //initializes the arrays.
        this.facturaService.getFacturas().subscribe(facturasReturned => this.facturasArray = facturasReturned);
        this.filteredFacturasArray.set(this.facturasArray);
    }

    filterFacturas(): void{ // this method is likely the problem

        let text = this.searchBarService.searchTextSignal();

        if (!text) 
            this.filteredFacturasArray.set(this.facturasArray);
        
        this.filteredFacturasArray.set(this.facturasArray.filter(factura => factura?.numero.toString().includes(text)));
    }

    ngOnInit(): void {
        this.getFacturas();
    }
}

The templace uses ngFor like so:

<div class="item-container">
    <div class="item" *ngFor="let factura of filteredFacturasArray()"> 
         <!-- template for the items -->
    </div>
</div>

So, everything boils down to how to make VistaFacturasComponent call filterFacturas() when searchBarService.searchTextSignal() updates. Any ideas?


Solution

  • Thanks to @Storytellerr's idea and subsequent error message, I had this idea and it ended up working (it might look ugly and unreadable but it works):

    filterText: Signal<string> = computed( () => this.searchBarService.searchTextSignal().replace(/^\D+/g, ''));
    
    filteredFacturasArray: Signal<Factura[]> = computed(() => this.facturasArray.filter(factura => factura?.numero.toString().includes(this.filterText())));
    

    basically defining a filterText computed that depends on searchBarService.searchTextSignal(), and then defining filteredFacturasArray as another computed that depends on filterText. Because both of these values directly depend on searchBarService.searchTextSignal(), whenever it changes they update automatically.