Playground
The Playground is another cool feature that NgDoc provides out of the box, it's especially handy for creating dynamic demos of your components and directives, to give your users the opportunity to play with them.
Creating a playground
In the ng-doc.page.ts
file, add the playgrounds
field, which must match the
interface. A playground config is a regular object whose key is the name of the playground (which you should use to display it on the page) and whose value is the config itself, for example:
For the template you can also use your real selector, but we recommend using
ng-doc-selector
to avoid cases where your playgrounds stop working when the selector is changed during refactoring.
If you don't need to render all possible selectors of your component, you can use the
selector
field to specify the selectors that you want to see in your playground.
If your target component is standalone, you don't need to import anything, NgDoc will care about it.
import { NgDocPage } from '@ng-doc/core';
import { NgDocTagModule, NgDocTagComponent } from '@ng-doc/ui-kit';
import { PageModule } from './ng-doc.module';
const MyAwesomePage: NgDocPage = {
playgrounds: {
TagPlayground: {
target: NgDocTagComponent ,
template: `<ng-doc-selector>Tag Label</ng-doc-selector>`,
},
},
};
export default MyAwesomePage;
target
- The Angular Component/Directive class that will be used for the playground (you should import its module in theimports
field if it's not standalone)template
- The template that will be used for the playground, you can use the Angular syntax inside, but it's value cannot be provided dynamically, so you can't use variables or functions there, value of this property should be static.<ng-doc-selector>
- is a unique tag that will be dynamically replaced with your component's selector, and if your component has multiple selectors, NgDoc will also create a view for each possible selector.
Displaying
To display the created playground on the page, you should use the playground
method from
, passing the key of your playground to it as follows
{{ NgDocActions.playground("TagPlayground") }}
NgDoc will recognize
field types and creates controls for them, which allow you to change their values and see how the component changes.
Input types recognition
There is no magic, NgDoc can only recognize simple type such as string
, number
, boolean
, or Type Alias types which are union of string
, number
, boolean
.
It can't recognize complex types such as Interface
, Class
or Enum
, but you can create your own custom controls for them to teach NgDoc doing that, read more about it in the
Multiple selectors
If your component has multiple selectors, NgDoc will create a view for each of them, to make it work correctly, you need to use the ng-doc-selector
tag in your template, which will be replaced with the selector of your component.
If you don't need to render all possible selectors of your component, you can use the
selectors
field in the playground configuration or action call to specify the selectors that you want to see in your playground.
import { NgDocPage } from '@ng-doc/core';
import { NgDocButtonComponent } from '@ng-doc/ui-kit';
const MyAwesomePage: NgDocPage = {
playgrounds: {
TagPlayground: {
target: NgDocButtonComponent ,
template: `<ng-doc-selector>Button</ng-doc-selector>`,
},
},
};
export default MyAwesomePage;
Inputs used in the template
If you are setting the value of an input using the template playground, NgDoc will ignore this input for the sidebar. Thus, you can pass references to HTML elements or other components into inputs using Angular syntax.
However, if you simply want to set a default value for an input and still keep control in the sidebar to manage its value, use the
or
NgDocPlaygroundOptions.inputs properties of the playground configuration.
NgDocPlaygroundOptions.defaults
import { NgDocPage } from '@ng-doc/core';
const MyAwesomePage: NgDocPage = {
playgrounds: {
TagPlayground: {
target: MyComponent,
template: `
You can also use "ng-doc-selector" here instead of your real selector
<my-component [input ]="elementRef"></my-component>
<input #elementRef value="Hello, World!">
`,
},
},
};
export default MyAwesomePage;
Optional content
Some components may support displaying other child components with
, and they may be optional, or you just want to make some content in the playground optional, to do this you can use the content
field in your playground configuration, for example:
If you provide some component in the
content
field, you must import it in theimports
field, if this component is not standalone you must import its module.
import { NgDocPage } from '@ng-doc/core';
import { NgDocTagComponent , NgDocIconComponent } from '@ng-doc/ui-kit';
const MyAwesomePage: NgDocPage = {
imports: [NgDocIconComponent ],
playgrounds: {
TagIconPlayground: {
target: NgDocTagComponent ,
template: `
<ng-doc-selector>
{{content.icon}}
Tag Label
</ng-doc-selector>`,
content: {
icon: {
label: 'email icon',
template: '<ng-doc-icon icon="at-sign" [size]="16"></ng-doc-icon>',
},
},
},
},
};
export default MyAwesomePage;
NgDoc will create new control in the Content
section that allows you to display or hide dynamic content.
Custom data and variables
To make your playgrounds more lively and dynamic you can use data
field, and put any data you want in it, to use it in your template, for example like that:
import { NgDocPage } from '@ng-doc/core';
import { NgDocTagComponent } from '@ng-doc/ui-kit';
const MyAwesomePage: NgDocPage = {
playgrounds: {
TagDataPlayground: {
target: NgDocTagComponent ,
template: `<ng-doc-selector>{{data.array | json}}</ng-doc-selector>`,
data: {
array: [1, 2, 3],
},
},
},
};
export default MyAwesomePage;
Directives
You can also create playgrounds for directives in the same way as for components:
import { NgDocPage } from '@ng-doc/core';
import { NgDocRotatorDirective } from '@ng-doc/ui-kit';
import { PageModule } from './ng-doc.module';
const MyAwesomePage: NgDocPage = {
playgrounds: {
RotatorPlayground: {
// We don't import anything else, because `NgDocRotatorDirective ` is standalone
target: NgDocRotatorDirective ,
template: `<button ngDocRotator>Button</button>`,
},
},
};
export default MyAwesomePage;
Pipes
It's also possible to create playgrounds for pipes, let's say we have a simple FormatDatePipe
:
import { Pipe , PipeTransform } from '@angular/core';
@Pipe ({
name: 'formatDate ',
standalone: true,
})
export class FormatDatePipe implements PipeTransform {
/**
* Transform pipe method
* @param value - ISO date string
* @param display - Display format
* @param utc - Determines if the date should be displayed in UTC
*/
transform(
value: string,
display: 'date' | 'time' | 'datetime' = 'datetime',
utc: boolean,
): string {
const date: Date = new Date(value);
const timeZone: 'UTC' | undefined = utc ? 'UTC' : undefined;
if (display === 'date') {
return date.toLocaleDateString('en-US', { timeZone });
} else if (display === 'time') {
return date.toLocaleTimeString('en-US', { timeZone });
} else {
return date.toLocaleString('en-US', { timeZone });
}
}
}
In the same way as for components and directives, you need to use the target
field to specify the pipe class, and the template
field to specify the template for the playground:
If your pipe has parameters, you must not provide values for them in the template, because NgDoc will bind them to the playground controls.
import { NgDocPage } from '@ng-doc/core';
import { FormatDatePipe } from './format-date.pipe';
import { PageModule } from './ng-doc.module';
const MyAwesomePage: NgDocPage = {
playgrounds: {
DatePipePlayground: {
target: FormatDatePipe,
template: `{{'2023-06-05T08:00:00.000Z' | formatDate }}`,
},
},
};
export default MyAwesomePage;
Configuration
Each playground can be configured both in the ng-doc.page.ts
file and when calling the rendering function
. In this case, the configuration from the template will overwrite the configuration in ng-doc.page.ts
. You can find all available options in the
interface.
Please be careful with the closing brackets
}
in your template, because it can be interpreted as the end of theexpression.
nunjucks index.md// Will not work {{ NgDocActions.playground("My", {inputs: {a:1}}) }} // To fix it, you need to add a space after the closing bracket {{ NgDocActions.playground("My", {inputs: {a:1} }) }}
For example, you can display a component without the side panel and with modified default input values like this:
{{ NgDocActions.playground("ButtonPlayground", {hideSidePanel: true, selectors: "button[ng-doc-button-flat]", inputs: {size: "small"}, data: {label: "Small Button"} }) }}
Unrecognized inputs
NgDoc does not automatically recognize some inputs, such as inputs defined within the
decorator using the inputs
property. To make NgDoc display them, you need to manually specify them in the playground configuration, for example:
You can also provide
instead of the type, to customize the control for this input.
NgDocPlaygroundControlConfig
import { NgDocPage } from '@ng-doc/core';
import { NgDocTagComponent } from '@ng-doc/ui-kit';
const MyAwesomePage: NgDocPage = {
imports: [NgDocTagModule],
playgrounds: {
TagDataPlayground: {
target: NgDocTagComponent ,
template: `<ng-doc-selector>My Tag</ng-doc-selector>`,
controls: {
// Key is the name of the input , value is the type of the input
myInput: 'string',
anotherInput: 'number',
},
},
},
};
export default MyAwesomePage;
For more complex types such as type aliases, you should specify the name of your type in the type
field. If for any reason you don't have it, you can specify NgDocTypeAlias
, an internal one that will prompt the playground to create a field with selectable values that you pass to options
.
import { NgDocPage } from '@ng-doc/core';
import { NgDocTagComponent } from '@ng-doc/ui-kit';
const MyAwesomePage: NgDocPage = {
imports: [NgDocTagModule],
playgrounds: {
TagDataPlayground: {
target: NgDocTagComponent ,
template: `<ng-doc-selector>My Tag</ng-doc-selector>`,
controls: {
size: { type: 'Size', options: ['small', 'medium', 'large'] },
color: { type: 'NgDocTypeAlias', options: ['primary', 'secondary', 'success', 'danger'] },
},
},
},
};
export default MyAwesomePage;