04.-UI-Inheritance

One of the major features of Narik is UI inheritance. As you can inherit from a component ts class, you can inherit from a base HTML file in a component template. It's completely different from the content projection. In UI inheritance, unlike content projection, no need to have two different components, actually all part of the created UI(UI created after apply inheritance) has one ts file.

Whit this feature you can create multiple components with one HTML UI.

How you should do that

  1. Create Templates

    First of all, you should define your templates. a template is a HTML file like other HTML files inside your application. it contains HTML tag, you're angular component's tag, directives and... But also it can contain narik-section. narik-section specify places that can be customized by views use this template.

    for example :

    This is default Narik template for detail(Edit) forms:

    <narik-busy-indicator>
    <narik-mat-toolbar toolbarKey="{{config && config.toolbarKey ? config.toolbarKey : 'detailToolBar'}}"> </narik-mat-toolbar>
    <mat-card>
    <form
    #form="ngForm"
    novalidate
    name="frmDetail"
    >
    <div narik-section="formContent"></div>
    </form>
    </mat-card>
    </narik-busy-indicator>

    Every view that wants to use this template, can only change narik-section sections. Each view can have multiple narik-section with different names.

    You can have multiple templates and put them wherever you want inside your application structure.

  2. Config Template Resolver

    After You define templates, you should specify how they used. For this, you should define a TemplateResolver class. this class must have a Resolve method that receives a key and returns template information. TemplateResolver Example:

    class TemplateResolver {
    Resolve(key) {
    switch (key) {
    case "NarikListUi":
    return {
    template: "",
    templateUrl: "./src/app/templates/list-template.html"
    };
    case "NarikDetailUi":
    return {
    template: "",
    templateUrl: "./src/app/templates/detail-template.html"
    };
    case "WidgetDesignUi":
    return {
    template: "",
    templateUrl: "./src/app/templates/widget-design-template.html"
    };
    default:
    break;
    }
    }
    }

    The templateUrl should be a relative path to tsconfig.app.json.

    This sample says that if some view request "NarikListUi" template, "./src/app/templates/list-template.html" will be returned.

    Resolve method output is an object with two fields: template and templateUrl.

    If the template field has value, it will be used, otherwise, templateUrl will be used. Maybe you use template when your template is small and you don't want to create an HTML file for that.

    After you define TemplateResolver class you must introduce it to webpack.

    To do this, change extra-webpack.config.js like this:

    var NarikCompilerPlugin = require("narik-webpack-tools/narik-compiler-plugin");
    var TemplateResolver = require("./build-tools/template-resolver");
    module.exports = {
    module: {
    rules: [
    {
    test: /\.tsx?$/,
    use: [
    {
    loader: "narik-webpack-tools",
    options: {
    resolver: new TemplateResolver()
    }
    }
    ]
    }
    ]
    },
    plugins: [
    new NarikCompilerPlugin({
    decoratorPattern: new RegExp(/Ui$/),
    resolver: new TemplateResolver({})
    })
    ]
    };
  3. Use Template

    To use templates, Narik provides you with one decorator, @NarikBaseTemplate.

    See this example:

    import { NarikBaseTemplate } from "narik-core";
    import { NarikUiDetailForm } from "narik-ui-material";
    import { Component, Injector } from "@angular/core";
    @NarikBaseTemplate("NarikDetailUi")
    @Component({
    templateUrl: "event-type-detail.component.html"
    })
    export class EventTypeDetailComponent extends NarikUiDetailForm<any> {
    static readonly COMPONENT_NAME = "EventTypeDetailComponent";
    constructor(injector: Injector) {
    super(injector);
    }
    }

    In this example EventTypeDetailComponent uses "NarikDetailUi" as template for it's view.

    And "event-type-detail.component.html" is like this:

    <ng-template #formContent>
    <narik-dynamic-form [model]="currentEntity" [fields]="fields"></narik-dynamic-form>
    <narik-color-input cpPosition='left' label="{{'color' | translate}}" [itemClass]="'color-picker'" [(ngModel)]="currentEntity.color"></narik-color-input>
    </ng-template>

    If you don't want to make any changes in template, you're component will be like this:

    import { NarikBaseTemplate } from "narik-core";
    import { NarikUiListForm } from "narik-ui-set";
    import { Component, Injector } from "@angular/core";
    @NarikBaseTemplate("NarikListUi")
    @Component({
    template: ""
    })
    export class GeneralListComponent extends NarikUiListForm<any> {
    static readonly COMPONENT_NAME = "GeneralListComponent";
    constructor(injector: Injector) {
    super(injector);
    }
    }
  4. Define Custom Template Decorators (This section is optional)

    Many times you have a lot of views that use templates, so the probability of error in Template key writing is high. To prevent this problem you can create your custom decorators.

    for example this sample shows the decorator for "NarikListUi":

    import { TypeDecorator } from "@angular/core";
    import { applyBaseTemplate } from "narik-core";
    export function NarikListUi() {
    const typeDecorator: TypeDecorator = <TypeDecorator>(
    function TypeDecorator(cls: any) {
    return applyBaseTemplate(cls, "NarikListUi");
    }
    );
    return typeDecorator;
    }

    So the previous sample can be changed:

    import { NarikUiListForm } from "narik-ui-set";
    import { Component, Injector } from "@angular/core";
    import { NarikListUi } from "../template-decorators/template.decorator";
    @NarikListUi()
    @Component({
    template: ""
    })
    export class GeneralListComponent extends NarikUiListForm<any> {
    static readonly COMPONENT_NAME = "GeneralListComponent";
    constructor(injector: Injector) {
    super(injector);
    }
    }

Be careful : The process of creating view from base templates takes place at build time, not runtime.

You can see more complete examples in these Narik samples and starters

narik-material-starter narik-material-demo narik-devextreme-demo narik-devextreme-starter