Interface ComponentOptions<T>

interface ComponentOptions<T = Type<any>> {
    disabledFeatures?: ("internals" | "shadow")[];
    encapsulation?:
        | "custom"
        | "template"
        | "shadow-dom"
        | "shadow-dom-template";
    extend?: (keyof HTMLElementTagNameMap)
    | `${string}-${string}`;
    formAssociated?: boolean | Type<ValueControl>;
    imports?: (readonly any[] | Type<any>)[];
    selector: string;
    shadowDomDelegatesFocus?: boolean;
    shadowDomMode?: ShadowRootMode;
    shadowRootInit?: Partial<ShadowRootInit>;
    styles?: string | { [key: string]: string }[];
    template?: string | DomNode;
    templateUrl?: string | TemplateUrl;
    zone?: ZoneType;
}

Type Parameters

Properties

disabledFeatures?: ("internals" | "shadow")[]
encapsulation?: "custom" | "template" | "shadow-dom" | "shadow-dom-template"

An encapsulation policy for the template and CSS styles. One of: 'custom': Use global CSS without any encapsulation. 'shadow-dom': Use Shadow DOM v1 to encapsulate styles.

'template': like 'custom', with load the template from the document ('index.html' file) that had the same id as the component "selector". 'shadow-dom-template': like 'shadowDom', and load template by selector id.

Both 'template' & 'shadow-dom-template' encapsulation type: should had attributes name like lowercase, the browser itself, will convert all attributes to lowercase

		personAge = input<number>(20, {alias: 'personage'});
propName = input<string>(undefined, {alias: 'propname'});
saveButtonClick = output<Persons>({alias: 'savebuttonclick'});
readonly view = view(HTMLFormElement);

any app root element as

<app-root></app-root>

the supported bind options is 'One way binding *(as passing data only)' and 'template parsing' and 'event binding' syntax, HTML (angular) like. it load its attributes from 'window object'

so to pass date to A root element,

<script>
const appVersion = '0.1.504';
function onRootAppClick() {
console.log('root app clicked');
}
function onSave(data){
console.log('root app save', data);
}
</script>
<app-root [version]="appVersion"
onclick="onRootAppClick()"
(save)="onSave()" >
</app-root>

default is 'custom'

extend?: (keyof HTMLElementTagNameMap) | `${string}-${string}`

what basic element should the new component inherit from, the tag name to inherit from as 'a', 'div', 'table', 'td', 'th', 'tr', etc ... also, support extends a custom element tag name.

formAssociated?: boolean | Type<ValueControl>

Create a custom form-associated element with HTMLElement.attachInternals default: false

if the value is true it is expected from the model class to implement ValueControl<T> interface

otherwise you can register another class that implement ValueControl<T>, in case if you want split the model and the value controller.


@Component({
selector: 'custom-message',
template: `
<label for="message">Message</label>
<textarea id="message" [(value)]="message" [disabled]="disabled" (change)="onMessageChange($event.target.value)"></textarea>
`,
formAssociated: true,
// formAssociated: CustomMessage,
})
export class CustomMessage implements ValueControl<string> {

private message: string | null = '';
private disabled: boolean = false;
private _onChange: (_: any) => void = () => {};

writeValue({ value, mode }: WriteValueOptions<string>) {
this.message = mode !== 'reset' ? value : '';
}

registerOnChange(fn: (_: any) => void): void {
this._onChange = fn;
}

setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
}

onMessageChange(message: string) {
this._onChange(message);
}

}


export class CustomInputValueControl implements ValueControl<number> {

private _value: number | null = null;
private _disabled: boolean = false;
private _onChange: (_: any) => void = () => {};

writeValue({ value, mode }: WriteValueOptions<number>) {
this._value = mode !== 'reset' ? value : null;
}

registerOnChange(fn: (_: any) => void): void {
this._onChange = fn;
}

setDisabledState(isDisabled: boolean) {
this._disabled = isDisabled;
}

}

@Component({
selector: 'custom-input',
extend: 'input',
formAssociated: CustomInputValueControl,
})
export class CustomInputElement {

view = view<HTMLInputElement>();

onInit() {
this.view.type = 'number';
}
}
imports?: (readonly any[] | Type<any>)[]

The imports property specifies the component's template dependencies — those directives, components, and pipes that can be used within its template.

selector: string

a tag name for the component, if the tag name is valid custom element name, the view class will be a custom element, otherwise an HTMLUnknownElement will be created

shadowDomDelegatesFocus?: boolean

default: false

shadowDomMode?: ShadowRootMode

default: 'open' when encapsulation used, otherwise it is undefined and will not attach shadow root element.

shadowRootInit?: Partial<ShadowRootInit>

shadow root initialization options, default mode: open, delegatesFocus: false and slotAssignment: manual

styles?: string | { [key: string]: string }[]

style for this element

template?: string | DomNode

template: html string if template === null || undefined ==> it had nothing to render, and may be inherit from an html element

write a template, as inline string, represent a a valid html.

templateUrl?: string | TemplateUrl

add html file url path to fetch, templateUrl had propriety than template, and will override it.

Can provide file name as "person-view.html" will resolved as 'http://site-address.org/persin-view.html',

OR as an object { moduleMeta: import.meta, filename: 'person-edit.html' } let (import.meta = '/person/person.js') will resolved as 'http://site-address.org/person/person-edit.html',

OR as an object { moduleMeta: import.meta } let (import.meta = '/person/person.js') will resolved as 'http://site-address.org/person/person.html'.

if url not found, component will not be defined,

if you didn't use webpack or rollup.js or any bundler, you should copy the html files to its folder by yourself.

zone?: ZoneType
  • use manual for no zone.js patch effect applied, and used for manual change detection for heavily process components.

  • use proxy zone for automatic detect changes without use of zone.js

  • use aurora for detection events like rxjs observables, setTimeout, setInterval and fetch and XMLHttpRequest, etc... make sure that zone.js is imported in the polyfills module.

the default value is the platform zone type which can be changed by:

bootstrapZone('manual')
bootstrapZone('proxy')
bootstrapZone('aurora')

if bootstrapZone never been called, then the default zone is a manual.