Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/ciccio-90/fg-dynamic-component
Create an Angular standalone signals based dynamic components tree through a JSON configuration with full life-cycle support for inputs, outputs, attributes, reactive forms and expressions binding evaluation.
https://github.com/ciccio-90/fg-dynamic-component
angular angular2 component dynamic input life-cycle ng output
Last synced: 24 days ago
JSON representation
Create an Angular standalone signals based dynamic components tree through a JSON configuration with full life-cycle support for inputs, outputs, attributes, reactive forms and expressions binding evaluation.
- Host: GitHub
- URL: https://github.com/ciccio-90/fg-dynamic-component
- Owner: ciccio-90
- License: mit
- Created: 2024-03-09T15:17:27.000Z (10 months ago)
- Default Branch: main
- Last Pushed: 2024-03-21T11:48:23.000Z (9 months ago)
- Last Synced: 2024-11-14T23:13:43.859Z (about 1 month ago)
- Topics: angular, angular2, component, dynamic, input, life-cycle, ng, output
- Language: TypeScript
- Homepage:
- Size: 294 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# fg-dynamic-component
Create an Angular standalone signals based dynamic components tree through a JSON configuration with full life-cycle support for inputs, outputs, attributes, reactive forms and expressions binding evaluation.
Compatibility with Angular
| Angular | fg-dynamic-component | NPM package |
| ------- | -------------------- | ----------------------------- |
| 17.2.4 | 1.1.1 | `fg-dynamic-component@^1.1.1` |
| 17.2.4 | 1.1.0 | `fg-dynamic-component@^1.1.0` |
| 17.2.4 | 1.0.2 | `fg-dynamic-component@^1.0.2` |
| 17.2.4 | 1.0.1 | `fg-dynamic-component@^1.0.1` |## Installation
```bash
$ npm install fg-dynamic-component --save
```## Usage
### FGDynamicComponent
Import `FGDynamicComponent` where you need to render dynamic components:
```ts
import { FGDynamicComponent } from "fg-dynamic-component";@NgModule({
imports: [FGDynamicComponent]
})
export class MyModule {}
```Then in your component's template include `` where you want to render component
and bind from your component class type of component to render:```ts
import { FGDynamicService, FGDynamicItem } from "fg-dynamic-component";FGDynamicService.registerComponent("MyDynamicComponent1", MyDynamicComponent1);
FGDynamicService.registerComponent("MyDynamicComponent4", import("...").then(m => m.MyDynamicComponent4));
FGDynamicService.registerComponent("MyDynamicComponent5", async () => (await import("...")).MyDynamicComponent5);@Component({
selector: "my-component",
template: ``
})
class MyComponent {
configuration = signal({
type: "MyDynamicComponent1",
items: [
{
type: MyDynamicComponent2
},
{
type: import("...").then(m => m.MyDynamicComponent3)
},
{
type: "MyDynamicComponent4"
},
{
type: "MyDynamicComponent5"
},
{
type: async () => (await import("...")).MyDynamicComponent6
},
{
type: () => import("...").then(m => m.MyDynamicComponent7)
}
]
} as FGDynamicItem);
}
```#### Standalone API
You may use `` as a standalone component:
```ts
import { FGDynamicComponent, FGDynamicService, FGDynamicItem } from "fg-dynamic-component";FGDynamicService.registerComponent("MyDynamicComponent4", import("...").then(m => m.MyDynamicComponent4));
FGDynamicService.registerComponent("MyDynamicComponent5", async () => (await import("...")).MyDynamicComponent5);@Component({
selector: "my-component",
template: ``,
imports: [FGDynamicComponent],
standalone: true
})
class MyComponent {
configuration = signal({
items: [
{
type: MyDynamicComponent2
},
{
type: import("...").then(m => m.MyDynamicComponent3)
},
{
type: "MyDynamicComponent4"
},
{
type: "MyDynamicComponent5"
},
{
type: async () => (await import("...")).MyDynamicComponent6
},
{
type: () => import("...").then(m => m.MyDynamicComponent7)
}
]
} as FGDynamicItem);
}
```_NOTE:_ You can declare components to dynamically load in static and/or dynamic way using or not the FGDynamicService.
### Inputs and Outputs
You can pass `inputs` and `outputs` to your dynamic components:
```ts
@Component({
selector: "my-component",
template: ``,
imports: [FGDynamicComponent],
standalone: true
})
class MyComponent {
configuration = signal({
type: MyDynamicComponent1,
inputs: {
hello: "world",
something: () => "can be really complex"
},
outputs: {
onSomething: (type) => alert(type)
}
} as FGDynamicItem);
}@Component({
selector: "my-dynamic-component1",
template: "Dynamic Component 1"
})
class MyDynamicComponent1 {
@Input()
hello: string;
@Input()
something: Function;
@Output()
onSomething = new EventEmitter();
}
```You can update your inputs passing expressions binding using a view model and they will trigger standard Angular's life-cycle hooks
(of course you should consider which change detection strategy you are using).```ts
@Component({
selector: 'my-component',
template: ``,
imports: [FGDynamicComponent],
standalone: true
})
class MyComponent {
configuration = signal({
type: MyDynamicComponent1,
inputs: {
hello: '$vm().count % 2 === 0 ? $vm().message : \'Hello World!\''
},
outputs: {
onSomething: '$vm.update(viewModel => { ...viewModel, message: $event, count: viewModel.count + 1 })'
}
} as FGDynamicItem);
viewModel = model({ message: 'Hello World!', count: 0 });
}@Component({
selector: 'my-dynamic-component1',
template: 'Dynamic Component 1'
})
class MyDynamicComponent1 {
@Input()
hello: string;
@Input()
something: Function;
@Output()
onSomething = new EventEmitter();
}
```### Attributes
You can declaratively set attributes, as you would inputs.
```ts
@Component({
selector: "my-component",
template: ``
})
class MyComponent {
configuration = signal({
type: MyDynamicComponent1,
attributes: {
"my-attribute": "attribute-value",
class: "some classes",
disabled: "$vm().isDisabled"
}
} as FGDynamicItem);
viewModel = model({ isDisabled: true });
}
```### Reactive Forms
You can declaratively set attributes to activate model binding, form control status (enabled/disabled) and validations with your ControlValueAccessor components.
> **Attributes**:
>
>- name: used to attach the new control to the input form group (must match the view model property name).
>- disabled: specifies that an input field should be disabled.
>- maxlength: specifies the maximum number of characters allowed in an input field.
>- minlength: specifies the minimum number of characters allowed in an input field.
>- min: specifies the minimum value for an input field.
>- max: specifies the maximum value for an input field.
>- pattern: specifies a regular expression that the input field's value is checked against.
>- required: specifies that an input field must be filled.
>- email: defines a field automatically validated to ensure it is a properly formatted e-mail address.```ts
@Component({
selector: "my-component",
template: ``
})
class MyComponent {
configuration = signal({
type: MyDynamicComponent1,
attributes: {
name: "data.firstName",
disabled: "$vm().metadata.firstName.disabled",
maxlength: 20,
required: true
}
} as FGDynamicItem);
viewModel = model({ data: { firstName: "Jhon" }, metadata: { firstName: { disabled: false } } });
formGroup = signal(new FormGroup({}));
}
```## Contributing
You are welcome to contribute to this project.
Simply follow the [contribution guide](/CONTRIBUTING.md).## License
MIT © [Francesco Guagnano]([email protected])