Search code examples
angulartypescript

Fetching variables from backend in non-injection context


I have the following routes:

const DATA_CHILDREN: any[] = [{
  name: 'Child page',
  url: 'child-url'
}, {
  name: 'Child page two',
  url: 'child-url-two'
}];

const routes: Routes = [{
  path: 'data/some-url',
  loadChildren: ...
  component: SomeComponent,
  data: {
    pages: MENU_PAGES,
    children: DATA_CHILDREN,
  }
}];

and I want to fetch the DATA_CHILDREN from my backend. I've tried converting DATA_CHILDREN into a Promise, e.g.

let getDataChildren = (): Promise<Page[]> => {
  return inject(FormService).findRoutes();
};

and this leaves me with:

Uncaught RuntimeError: NG0203: inject() must be called from an injection context

How can I handle this?


Solution

  • You can try and use a resolver to first fetch data from your backend. Before you process it see ref for using the resolver.

    You can use this code as a guide ultimately this should work in theory

    @Injectable({
      providedIn: 'root'
    })
    export class DataChildrenResolver implements Resolve<Page[]> {
      constructor(private formService: FormService) {}
    
      resolve(): Observable<Page[]> {
        return this.formService.findRoutes(); //<- data from the backend
      }
    }
    

    You can then modify your Routes to use the Resolver or children data before the route is activated

    const routes: Routes = [{
      path: 'data/some-url',
      component: Anycomponent,
      resolve: {
        children: DataChildrenResolver 
      },
      data: {
        pages: MENU_PAGES
      }
    }];
    

    Update your components to use the resolved Data

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    
    @Component({
      selector: 'app',
      templateUrl: './Yourcomponent.html'
    })
    export class Yourcomponent implements OnInit {
      children: Page[];
    
      constructor(private route: ActivatedRoute) {}
    
      ngOnInit(): void {
        // accessing data
        this.children = this.route.snapshot.data['children'];
      }
    }
    

    Below is how your route-path structure should be for it to work (if you have restrictions on your route-path).

    {
     path: 'base'
     canActivate: [BaseGuard],
     resolve: {data: BaseDataResolver}
     children: [
      {
        path: 'child',
        guards: [ChildGuard],
        component: ChildComponent,
        resolve: {childData: ChildDataResolver}
       }
     ]
    }