Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Storybook - prop knobs and ng-content

I'm building out an Angular app with Storybook. I want my stories to have controllable knobs, but some of these components take ng-content.

I'm having trouble getting these two to work together, because, from what I've found, passing content into a component using Storybook involves setting a template on the story. Unfortunately, template seems to essentially overwrite Storybook's knob-passed props.

Here's the example:

button.component.ts

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'ui-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.scss']
})
export class ButtonComponent implements OnInit {
  types: String[] = [];

  constructor() {}

  ngOnInit(): void {}

  typeClasses(): String[] {
    return this.types.map(t => `button--${t}`);
  }
}

button.component.html

<a class="button" [ngClass]="typeClasses()">
  <ng-content></ng-content>
</a>

button.component.stories.ts

import { text, array } from '@storybook/addon-knobs';
import { ButtonComponent } from './button.component';

export default {
  title: 'ButtonComponent'
};

export const dark = () => ({
  moduleMetadata: {
    declarations: [ButtonComponent], // Removed if no template
    imports: []
  },
  // component: ButtonComponent, replaced with the below because of ng-content
  template: `<ui-button>Button content</ui-button>`, // Needed to pass arbitrary child content
  props: {
    types: array('class', ['dark']), // Ignored, because it's not in template
  }
});

Am I missing a better way to pass content in? Because I have to give a full template, it seems that any props not passed in that template aren't injected into the component, and so the knobs are rendered useless. This seems to mean that I should just get rid of props on all my component stories, and instead just pass them in through the template, but that would render them non-configurable in the served Storybook and defeat much of the point.

Am I doing this wrong? Is there a way to both A) pass content, and B) allow for props? The Angular Storybook guide doesn't seem to address this.

like image 302
Sasha Avatar asked Mar 31 '20 19:03

Sasha


1 Answers

Using the latest storybook version ("@storybook/angular": "^5.3.19"), this seems to be working. I've discovered it by pure luck:

export const Default = () => ({
    moduleMetadata: {
        declarations: [AppComponent],
    },
    props: {
        propInput: {
            foo: 1,
            bar: {
                baz: ["zxc"]
            }
        }
    },
    template: `<app-component [componentInput]="propInput"> Hello World </app-component>`,
});
like image 61
Rus Paul Avatar answered Sep 17 '22 16:09

Rus Paul