Search code examples
angularprimengstorybook

ANGULAR + PRIMENG + STORYBOOK: Error on NullInjectorError: No provider for InjectionToken app.config


I started a new angular APP:

ng new my-app

Then I added PrimeNG:

npm install primeng

Finally, I added StoryBook:

npx storybook@latest init

I created the a new component:

ng g c header

The component:

export class HeaderComponent implements OnInit {

  public user: User;
  public projects: Project[] = [];
  public mainProject: Project | undefined;
  public items: MenuItem[] = [];
  public loading: boolean = true;

  @ViewChild(Menu)
  public menu: Menu;

  constructor() { }

  ngOnInit(): void {

  }

}

And created a story for it:

const meta: Meta<HeaderComponent> = {
    title: 'HeaderComponent',
    component: HeaderComponent,
    decorators: [
        moduleMetadata({
            imports: [
                DropdownModule,
                ProgressSpinnerModule,
                AvatarModule,
                MenuModule,
                ButtonModule,
                FormsModule,
                BrowserAnimationsModule
            ],
            providers: [{ provide: ActivatedRoute, useValue: {} }]
        }),
    ],
};

export default meta;
type Story = StoryObj<HeaderComponent>;

export const Primary: Story = {
    args: {
        loading: true,
        projects: [{ name: "Project 1", main: true }, { name: "Project 2", main: false }],
        user: { username: "User Default", avatar: "data:image/png;base64...." },
        items: [{ label: "Perfil", icon: "pi pi-fw pi-user" }, { label: "Configurações", icon: "pi pi-fw pi-cog" }]
    },
};

And works fine! However, when I add a service in the component:

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

  constructor(@Inject(APP_CONFIG) private config: AppConfig, private http: HttpClient) { }

  public list(): Observable<Project[]> {
    return this.http.get<Project[]>(`${this.config.api.url}/projects`);
  }
}

And changed the story to:

const meta: Meta<HeaderComponent> = {
    title: 'HeaderComponent',
    component: HeaderComponent,
    decorators: [
        moduleMetadata({
            imports: [
                DropdownModule,
                ProgressSpinnerModule,
                AvatarModule,
                MenuModule,
                ButtonModule,
                FormsModule,
                BrowserAnimationsModule
            ],
            providers: [
                { provide: ActivatedRoute, useValue: {} },
                { provide: APP_CONFIG, useValue: { api: { url: "http://localhost:8500/api" } } }
            ]
        }),
    ],
};

export default meta;
type Story = StoryObj<HeaderComponent>;

export const Primary: Story = {
    args: {
        loading: true,
        projects: [{ name: "Project 1", main: true }, { name: "Project 2", main: false }],
        user: { username: "User Default", avatar: "data:image/png;base64...." },
        items: [{ label: "Perfil", icon: "pi pi-fw pi-user" }, { label: "Configurações", icon: "pi pi-fw pi-cog" }]
    },
};

I am getting this error:

R3InjectorError(Standalone[StorybookWrapperComponent])[ProjectService -> ProjectService -> InjectionToken app.config -> InjectionToken app.config]: NullInjectorError: No provider for InjectionToken app.config!

In the angular app works fine, no errors. Any ideas?


Solution

  • After talking with MarkB in StoryBook Discord Channel, I gotta the answer:

    const meta: Meta<HeaderComponent> = {
        title: 'HeaderComponent',
        component: HeaderComponent,
        decorators: [
            applicationConfig({
                providers: [
                    { provide: APP_CONFIG, useValue: { api: { url: 'http://localhost:8500/api' } }, },
                    { provide: ActivatedRoute, useValue: {} },
                    importProvidersFrom(HttpClientModule)
                ],
            }),
            moduleMetadata({
                imports: [
                    DropdownModule,
                    ProgressSpinnerModule,
                    AvatarModule,
                    MenuModule,
                    ButtonModule,
                    FormsModule,
                    BrowserAnimationsModule,
                ],
            }),
        ],
    };
    
    export default meta;
    type Story = StoryObj<HeaderComponent>;
    
    export const Primary: Story = {
        args: {
            loading: true,
            projects: [{ name: "Project 1", main: true }, { name: "Project 2", main: false }],
            user: { username: "User Default", avatar: "data:image/png;base64...." },
            items: [{ label: "Perfil", icon: "pi pi-fw pi-user" }, { label: "Configurações", icon: "pi pi-fw pi-cog" }]
        },
    };