Search code examples
angulartypescriptsignalsngrxstate-management

Loading Data dependend on signal property whenever the signalproperty changes in a Signal Store


I am using a signal store in my application to manage the state related to projects and sites. Here is my current implementation:

interface State {
  selectedProject: Project | null,
  selectedSite: Site | null,

  projects: Project[],
  sites: Site[],
}

export const Store = signalStore(
  withState<State>({
    selectedProject: null,
    selectedSite: null,

    projects: [],
    sites: []
  }),

  withMethods(state => {
    const sitesService = inject(SitesService);
    const projectsService = inject(ProjectsService);

    return {
      loadSites: async () => {
        const sites = await sitesService.getSites();
        patchState(state, { sites });
      },
      loadProjectsBySiteId: async (siteId: number) => {
        const projects = await projectsService.getProjectsBySiteId(siteId);
        patchState(state, { projects });
      },
      setSelectedSite: (selectedSite: Site) => {
        patchState(state, { selectedSite, selectedProject: null });
      },
      setSelectedProject: (selectedProject: Project) => {
        patchState(state, { selectedProject });
      }
    };
  }),

  withHooks({
    onInit({ loadSites }) {
      loadSites();
    }
  })
);

I need to load the projects whenever selectedSite changes. Currently, I am not sure about the best way to achieve this in my signal store setup.

I am either considering to use the withComputed in some way, or to do it inside the setter setSelectedSite (trigger here a fetch or ...)

What is the best practice for loading projects based on the selectedSite change in this context?


Solution

  • Basically this was my solution. I am not very sure If the updating of a store Value in an effect could potentially create Problems...

    withHooks({
    onInit({ loadSites, selectedSite, loadProjectsBySiteId }) {
      loadSites();
      effect(() => {
        const selectedSiteId = selectedSite()?.id;
        if(selectedSiteId) {
          loadProjectsBySiteId(selectedSiteId);
        }
      }, { allowSignalWrites: true });
    }