question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Angular - Stories redeclaring components in DynamicModule

See original GitHub issue

Is your feature request related to a problem? Please describe. I am building a component library, which contains primitive (independent) components as well as components that are a composition of other primitive and/or complex components. For simplicity’s sake I have a module for every exported component where I can define all nested components(modules) that it depends on.

When writing a story for such a component I expected this would work:

storiesOf('Button', module)
  .addDecorator(withKnobs)
  .addDecorator(
    moduleMetadata({
      imports: [ButtonModule],
    })
  )
  .add('default', () => ({
    component: ButtonComponent,
    props: {
      disabled: boolean('disabled', false)
    }
  }));

But this leads to the following error:

Promise rejection: Type ButtonComponent is part of the declarations of 2 modules: ButtonModule and DynamicModule! Please consider moving ButtonComponent to a higher module that imports ButtonModule and DynamicModule.

I have traced down that it comes from helpers.ts where it always creates a DynamicModule in which it declares the component mentioned in the story.

If I define the component in the story with template (instead of component) it works fine but the downside is that I have to manually mention all the props/bindings for knobs in the template.

  .add('default', () => ({
    template: '<my-button [disabled]="disabled">',
    props: {
      disabled: boolean('disabled', false)
    }
  }));

Describe the solution you’d like When writing stories for a component I would like to import the NgModule in which the component is declared using moduleMetadata decorator and use the components reference (not template) in stories together with props/bindings.

Describe alternatives you’ve considered

  1. Using the template, letting Storybook wrap a component around my component - it’s tedious to mention the bindings in the HTML string.
  2. Changed helpers.ts to NOT include my component in DynamicModule’s declarations - breaks the bindings altogether.

Are you able to assist bring the feature to reality? I have described what I have considered but I doubt I could provide an elegant solution to it.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:18 (10 by maintainers)

github_iconTop GitHub Comments

5reactions
MaximSagancommented, Apr 3, 2019

I have created a PR (#6346) for this. As has been discussed, the issue is that when Storybook sees a component specified in the form “component: MyComponent” it assumes that the component requires declaration, and hence we get the “MyComponent is part of the declarations of 2 modules” when it’s already been declared in an imported module (generally it’s feature module).

To solve this, I simply added a boolean option to the “story” object (the object where the component, props etc. are specified) called “requiresComponentDeclaration” which defaults to true (non-breaking change) but would be set to false in the situation that we’re describing.

You can check out the working example in my PR here.

Note: As @pascaliske alluded to, ideally we would check imported modules (and those modules’ imported modules recursively) to see if the component has been declared in one of them and then only declare the component of it hasn’t been, but I’m not sure if that’s possible with the APIs available to us.

2reactions
ThibaudAVcommented, Feb 1, 2021

On 5.1 the option requiresComponentDeclaration has been added and then quickly removed 🤣

added in v5.1.0-alpha.36 containing PR https://github.com/storybookjs/storybook/pull/6346 removed in v5.1.0-alpha.40 containing PR https://github.com/storybookjs/storybook/pull/6666 😈

if I don’t make a mistake : This problem means that storybook cannot detect that the component is already declared in an angular module (or sub module) imported by the story (see getExistenceOfComponentInModules function)

In any case that I have tested the getExistenceOfComponentInModules does the job correctly. To be able to identify the problematic case it would be necessary to have a way to reproduce it. can you give us a test repository with the error ?

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use relative angular component in Storybook?
List of module dependencies and component declarations. Stored as separate var because they are shared among all stories */ const modules ...
Read more >
Assemble a composite component - Storybook Tutorials
Create a TaskList component and an accompanying story file: ... import { Component, Input, Output, EventEmitter } from '@angular/core'; import { Task }...
Read more >
Dynamic component loader - Angular
An application might need to load new components at runtime. This cookbook shows you how to add components dynamically. See the live example...
Read more >
Building Components with Angular and Storybook
Storybook is an open source tool for developing UI components in isolation for React, Vue, and Angular. It makes building stunning UIs organised...
Read more >
Here is what you need to know about dynamic components in ...
Here is what you need to know about dynamic components in Angular · Component factory and compiler · Angular modules and ComponentFactoryResolver ·...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found