Angular - Stories redeclaring components in DynamicModule
See original GitHub issueIs 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
- Using the template, letting Storybook wrap a component around my component - it’s tedious to mention the bindings in the HTML string.
- 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:
- Created 5 years ago
- Reactions:2
- Comments:18 (10 by maintainers)
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.
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 ?