npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

json2component

v0.1.1

Published

A basic way of rendering json as angular components inspired by json2react.

Downloads

7

Readme

JSON2Component

I've got the question if there was an Angular library that does a similar thing to json2react - maybe there is - nonetheless we are here now with my somewhat whacky approach to it :P

If you have any suggestions for potential improvments I'd be grateful to hear them! 🍪

Live Example on StackBlitz

https://stackblitz.com/edit/json2component-example

Installation

This project is on npm now! To install it just run the following command inside your angular project:

> npm i json2component

How does it work?

To use this library import it into the module it's going to be used in. This can either be the AppModule or some sub module.

@NgModule({
  declarations: [AppComponent, CustomComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    JSON2ComponentModule.forRoot([
      { component: CustomComponent, name: 'custom-component' },
    ]),
  ],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

If you want to specify Angular components in the JSON schema you need to specify these components in the forRoot method of the module. It takes an array of objects represented by the IFactoryConfiguration interface. If you are not going to use Angular components provide an empty array.

After that you can start using the json-component component in the configured module. To render a view from JSON you need to specify a template that is compliant with the IJSONComponentSchema interface. An example schema is provided with the module.

Schema

The template schema consists of five properties:

type

This property is required

The type of element being generated. For now this projects supports:

  • p
  • h1
  • h2
  • div
  • img

Supported elements are also declared and listed in interfaces/HTMLElement.type.ts/NativeElement

{
    "type": "div"
}

You can also specify the name of an angular component registered in the forRoot method.

styles

This property is optional

An object containing key value pairs that represent css classes:

"styles" : {
  "background-color": "#121212",
  "font-family": "sans-serif"
}

content

This property is optional

Content that is being displayed inside an element like <h1>I like cookies</h1>

{
    "content": "I like cookies"
}

props

This property is optional

An object containing key value pairs that represent properties of an HTML element or Angular component.

{
    "type": "img",
    "props": {
        "src": "https://web.com/content/super-cute-dog.jpg"
    }
}

children

This property is optional

An array of Objects complient with the IJSONComponentSchema interface.

Specifing this property will insert new elements inside the parent.

{
    "type": "div",
    "children": [
        {
            "type": "h1",
            "props": {
                "innerHTML": "My favourite food"
            }
        },
        {
            "type": "p",
            "content": "Is cookies :3"
        }
    ]
}

Using custom components

As mentioned earlier you are also able to specify Angular components inside templates. To use them they first have to be imported in the modules forRoot method. After that they can be used as following:

{
  "type": "custom-component",
  "props": {
    "title": "Things I like",
    "customProps": {
      "someProp": ":3",
    },
  },
  "styles": {
    "_h1": {
      "display": "flex",
      "justify-content": "center",
    },
    "_div": {
      "display": "flex",
    },
  },
  "children": [ ... ]
}

Any property specified for a component will be set inside the component instance as a property of the class and can be accessed as such.

import { Component, OnInit } from '@angular/core';
import { ComponentProps, ICustomComponent, JSONComponentBase, StyleClasses } from '../shared/json2component';

@Component({
  selector: 'custom-component',
  template: `
    <h1 [ngStyle]="headerStyle">{{ title }}</h1>
    <div [ngStyle]="divStyle">
      <span *ngFor="let child of _children">
        <base-element [componentBase]="child"></base-element>
      </span>
    </div>
  `,
})
export class CustomComponent implements OnInit, ICustomComponent {
  // Default properties that are being set form the template
  public readonly _styles: StyleClasses;
  public readonly _props: ComponentProps;
  public readonly _children: JSONComponentBase[];
  public readonly _content: string;

  // The template definition of the current element
  public readonly _definition: JSONComponentBase;

  // Properties being set as props
  public title: string;
  public customProps: { someProp: string };

  public divStyle: StyleClasses;
  public headerStyle: StyleClasses;

  constructor() {}

  ngOnInit(): void {
    this.divStyle = this._styles._div;
    this.headerStyle = this._styles._h1;
  }
}

Due to limitations by the implementation of this feature you'll have to manually apply things like styling to the component. To do so you get access to all data specified for the component. To keep track of what properties are available by default make the component implement the ICustomComponent interface.

Component definition

You are able to acces the component definition of the component instance with the _definition property. It is of type JSONComponentBase and contains all data for the current node in the template and its children.

Apply styling

You can use the ngStyle directive to apply styling to elements inside the component by using the _style property. To keep apart the styling of different elements of a component you can keep them as seperate definitions inside the styles property in the template.

"styles": {
  "_h1": {
    // Styling for h1
  },
  "some-segment": {
    // Styling for some-segment
  }
}

In the component you can then store these styles in two different properties as shown in the example component above.

Access props

Everything specified in props is available in the _props property of the component class. Additionally every prop is also directly set as a property of the class with the key of the prop as its name.

Render children

If you want to specify children for your component you'll need to implement the process of displaying them by yourself. A very simple way of doing so is shown in the example component above. By importing the module you get access to the base-element component that is responsible for rendering a JSONComponentBase. You can use it by specifying such a component base that you get in the _children property for example.

<span *ngFor="let child of _children">
  <base-element [componentBase]="child"></base-element>
</span>

Example configuration

There is a sample schema provided with the module that can be imported from from the module directory to see how the schema can be used

app.component.ts

import { schema } from './shared/json2component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  _schema = schema;
}

That schema can then be used in a template to dynamically create components from that schema.

app.component.html

<json-component [template]="_schema"></json-component>

Using this schema will result in the following preview

alt text

Schema example code

{
  "type": "div",
  "styles": {
    "width": "100vw",
    "display": "flex",
    "align-items": "center",
    "flex-direction": "column"
  },
  "children": [
    {
      "type": "custom-component",
      "props": {
        "title": "Things I like",
        "customProps": { "someProp": ":3" }
      },
      "styles": {
        "_h1": { "display": "flex", "justify-content": "center" },
        "_div": { "display": "flex" }
      },
      "children": [
        {
          "type": "p",
          "content": "Dogs",
          "styles": {
            "display": "flex",
            "align-items": "center",
            "flex-direction": "column",
            "padding": "20px"
          },
          "children": [
            {
              "type": "img",
              "props": {
                "src": "https://images.pexels.com/photos/1805164/pexels-photo-1805164.jpeg"
              },
              "styles": { "margin-top": "10px", "max-width": "200px" }
            }
          ]
        },
        {
          "type": "p",
          "content": "Cookies",
          "styles": {
            "display": "flex",
            "align-items": "center",
            "flex-direction": "column",
            "padding": "20px"
          },
          "children": [
            {
              "type": "img",
              "props": {
                "src": "https://images.pexels.com/photos/890577/pexels-photo-890577.jpeg"
              },
              "styles": { "margin-top": "10px", "max-height": "300px" }
            }
          ]
        }
      ]
    },
    {
      "type": "p",
      "content": "Being able to center this div vertically",
      "styles": {
        "display": "flex",
        "align-items": "center",
        "flex-direction": "column"
      },
      "children": [
        {
          "type": "div",
          "styles": {
            "height": "250px",
            "width": "500px",
            "display": "flex",
            "flex-direction": "column",
            "justify-content": "center",
            "align-items": "center",
            "background-color": "#EFEFEF",
            "margin-top": "10px"
          },
          "children": [
            {
              "type": "div",
              "styles": {
                "width": "100px",
                "height": "100px",
                "background-color": "#121212"
              }
            }
          ]
        }
      ]
    }
  ]
}
export const schema = ((): string =>
  JSON.stringify({
    type: 'div',
    styles: {
      width: '100vw',
      display: 'flex',
      'align-items': 'center',
      'flex-direction': 'column',
    },
    children: [
      {
        type: 'custom-component',
        props: {
          title: 'Things I like',
          customProps: {
            someProp: ':3',
          },
        },
        styles: {
          _h1: {
            display: 'flex',
            'justify-content': 'center',
          },
          _div: {
            display: 'flex',
          },
        },
        children: [
          {
            type: 'p',
            content: 'Dogs',
            styles: {
              display: 'flex',
              'align-items': 'center',
              'flex-direction': 'column',
              padding: '20px',
            },
            children: [
              {
                type: 'img',
                props: {
                  src:
                    'https://images.pexels.com/photos/1805164/pexels-photo-1805164.jpeg',
                },
                styles: {
                  'margin-top': '10px',
                  'max-width': '200px',
                },
              },
            ],
          },
          {
            type: 'p',
            content: 'Cookies',
            styles: {
              display: 'flex',
              'align-items': 'center',
              'flex-direction': 'column',
              padding: '20px',
            },
            children: [
              {
                type: 'img',
                props: {
                  src:
                    'https://images.pexels.com/photos/890577/pexels-photo-890577.jpeg',
                },
                styles: {
                  'margin-top': '10px',
                  'max-height': '300px',
                },
              },
            ],
          },
        ],
      },
      {
        type: 'p',
        content: 'Being able to center this div vertically',
        styles: {
          display: 'flex',
          'align-items': 'center',
          'flex-direction': 'column',
        },
        children: [
          {
            type: 'div',
            styles: {
              height: '250px',
              width: '500px',
              display: 'flex',
              'flex-direction': 'column',
              'justify-content': 'center',
              'align-items': 'center',
              'background-color': '#EFEFEF',
              'margin-top': '10px',
            },
            children: [
              {
                type: 'div',
                styles: {
                  width: '100px',
                  height: '100px',
                  'background-color': '#121212',
                },
              },
            ],
          },
        ],
      },
    ],
  } as IJSONComponentSchema))();