DEV Community

Cover image for Storybook Addon AngularJS (1.x)
Tito
Tito

Posted on • Updated on

Storybook Addon AngularJS (1.x)

A few weeks ago I published the package storybook-addon-angularjs to help create stories for Storybook with AngularJS components.

Features:

  • Simple syntax
  • Supports integration with other addons like knobs and actions

The Tweet with the first announcement and a small screen capture:

Liquid error: internal

Creating a story with an AngularJS component is as simple as this:

import { storiesOf } from "@storybook/html";

import { withKnobs, text, number } from "@storybook/addon-knobs";
import { action } from "@storybook/addon-actions";

import { forModule } from "storybook-addon-angularjs";

storiesOf("Components/Demo", module)
  .addDecorator(withKnobs)
  .add(
    "default",
    forModule("myApp").createElement(compile => {
      const name = text("Name", "Jane");

      const foo = {
        bar: number("Value", 20, { range: true, min: 0, max: 30, step: 1 })
      };

      const onEvt = action("clicked");

      return compile`<demo-component
                       name="${name}"
                       foo="${foo}"
                       on-ev="${onEvt}(num, name)"></demo-component>`;
    })
  );
Enter fullscreen mode Exit fullscreen mode

This depends on Storybook 4+ and the HTML Addon.

The code for the addon:

GitHub logo titonobre / storybook-addon-angularjs

A simple addon to create Storybook stories with AngularJS components.

Storybook Addon for AngularJS (1.x)

npm npm GitHub issues GitHub Storybook

Note This addon is intended to be used with @storybook/html, available since Storybook 4.

Installation

Use your favorite 📦 package manager to install the addon in your project's devDependencies:

npm:

npm install --save-dev storybook-addon-angularjs
Enter fullscreen mode Exit fullscreen mode

Yarn:

yarn add --dev storybook-addon-angularjs
Enter fullscreen mode Exit fullscreen mode

Usage

This addon is flexible enough to let you choose how you want to write stories.

Your stories can be as simple as this:

export default {
  title: "QuoteCard",
  decorators: [withAngularJs("myApp")],
};
export const simpleTemplate = () => `
  <quote-card author="'Me'">
    It works with a simple template!
  </quote-card>
`;
Enter fullscreen mode Exit fullscreen mode

But you may choose something more advanced:

import { withKnobs, text } from "@storybook/addon-knobs";
import { action } from "@storybook/addon-actions";
import { html, withAngularJs } from "storybook-addon-angularjs";
class MockedAppService {
  constructor() {
    this.message =
…
Enter fullscreen mode Exit fullscreen mode

A working example:

GitHub logo titonobre / storybook-addon-angularjs-example

A working example with storybook-addon-angularjs. Moved to: https://github.com/titonobre/storybook-addon-angularjs




Feedback is appreciated.
Thanks for reading.

Oldest comments (9)

Collapse
 
theodesp profile image
Theofanis Despoudis

Amazing, will check it out

Collapse
 
hackily profile image
Neil

Looks great, will really help those of us still maintaining angularjS.

Any easy way to access the $scope?

Collapse
 
titonobre profile image
Tito

Hi Neil.
Do you have an example of what you are trying to achieve?

Collapse
 
hackily profile image
Neil • Edited

I have component examples in a non-storybook ui documentation that I'm trying to see if I can convert over, but a lot of these examples just dump functions into the $scope.

I can't show you the actual code, but this should illustrate what I'm trying to accomplish.

index.html

<div ng-controller="ExampleController">
  <my-ng-element props='innerProps'></my-ng-element>
</div>

script.js

myModule.controller('ExampleController', ['$scope', ...deps,  
  function($scope, ...deps) {
     $scope.clickFn = function() {alert('Click!')};
     $scope.innerProps = [
       //Component relies on controller as syntax
       {key: 'data-ng-click', val: 'ctrl.click()'},
       {key: 'aria-label', val: 'Some label'}
     ]
  }

index.html (rendered)

<div ng-controller="ExampleController">
  <my-ng-element props='innerProps'>
    <div class="has-dynamically-generated-props"
         ng-click="ctrl.clickFn()"
         aria-label="Some label"
    >
    </div>
  </my-ng-element>
</div>

So yeah, with the above, since ctrl is undefined, it just doesn't work. There's no direct controller scope access or support for controller as syntax.

I've found that to minimally change the existing code, I can do something like below, though it would be amazing if there was access to controller scope, or support for controller as syntax officially.

forModule("myApp").createElement(compile => {
  $scope = {};

  //Paste original code here
  $scope.clickFn = function() {alert('Click!')};
  $scope.innerProps = [
    // ctrl hard coded to become _prop0
    {key: 'data-ng-click', val: '_prop0.click()'},
    {key: 'aria-label', val: 'Some label'}
  ]
  //Add in hacky scopeShim workaround
  return compile`<my-ng-element scopeShim="${$scope}" props="${$scope.innerProps}"></my-ng-element>`;
})

There's a lot of examples, I'd like to do as much copy pasting as possible with preferably little to no additional editing of existing code, haha.

Hopefully the above makes sense, I also don't have access to my work codebase at the moment.

Thread Thread
 
titonobre profile image
Tito

My first approach was to expose the $scope.

Can you have a look at the first release here: github.com/titonobre/storybook-add...

And the example here: github.com/titonobre/storybook-add...

If it helps, I can add this back.

Thread Thread
 
titonobre profile image
Tito

@hackily Did you had the chance to try the first version of the addon?

Collapse
 
schemesonic profile image
Haldun YILDIZ

Great job, I will try in few days

Collapse
 
titonobre profile image
Tito

Hope it helps.
If something goes wrong just let me know.

Collapse
 
titonobre profile image
Tito

Finally v1 🎉

After a few attempts, I think this time I got this right.

With the new decorator withAngularJs, story can be as simple as this:

export default {
  title: "QuoteCard",
  decorators: [withAngularJs("myApp")]
};

export const simpleTemplate = () => `
  <quote-card author="'Me'">
    It works with a simple template!
  </quote-card>
`;

Check the new examples for more advanced uses.

You can even write stories in markdown with the MDX story format supported by Storybook.

New Features

  • New ways to write stories
  • Added support for hooks, thanks @is2ei
  • Added support for multiple modules, thanks @ofhouse

No Breaking Changes

Yes, you can migrate from v0.0.2 to v1.0 with no changes to your stories. 💪

Repository: github.com/titonobre/storybook-add...

Working Examples: storybook-addon-angularjs.now.sh