Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2/4 : Override component from another module

I'm using angular 4.3, typescript 2.2

I want to create multiple applications (websites) based on the same codebase. All websites will be pretty much identical, but some of them might have some additional/different logc/templates.

My idea is to create a core Module (containing mainly components), and then have the applications use that module to build upon it, and overload as needed: - the styles - the templates (replace completely the template, or just modify a part of it)

  1. How can I override the components used in the core module?

I only managed to override the components wich are used explicitely in the routing, but I cannot override child components called directly in the templates of the Core module. Do I need to inject these components dynamically?

  1. When inheriting a component, is it possible to only override part of the parent template?

I guess each template part that needs to be overriden would have to be changed to a component in the core module (and then back to question #1 to use inherited component in the child apps)

Thanks

like image 718
David Avatar asked Jul 19 '17 12:07

David


1 Answers

Question #1

Here is a solution that worked for me

Step 1

I put all my core components in a core module in a core app.

Step 2

I declared the following CustomModule fonction in the core app

declare var Reflect : any;

export function CustomModule(annotations: any)
{
  return function (target: Function)
  {
    let parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    let parentAnnotations = Reflect.getMetadata("annotations", parentTarget);

    let parentAnnotation = parentAnnotations[0];
    Object.keys(parentAnnotation).forEach(key =>
    {
      if (parentAnnotation[key] != null)
      {
        if (typeof annotations[key] === "function")
        {
          annotations[key] = annotations[key].call(this, parentAnnotation[key]);
        }
        else if (typeof Array.isArray(annotations[key]))
        {
          let mergedArrayItems = [];
          for (let item of parentAnnotation[key])
          {
            let childItem = annotations[key].find(i => i.name  == item.name);
            mergedArrayItems.push(childItem ? childItem : item);
          }

             annotations[key] = mergedArrayItems;
        }
        else if (annotations[key] == null)
        {  // force override in annotation base
          annotations[key] = parentAnnotation[key];
        }
      }
    });

    let metadata = new NgModule(annotations);

    Reflect.defineMetadata("annotations", [metadata], target);
  };
}

Step 3

In another application, I created a different module called InheritedModule, I created components that inherit from the components in the CoreModule. The inherited component must have the same name and the same selector as the parent component.

Step 4

I made InheritedModule inherit from the CoreModule. InheritedModule was declared with the CustomModule annotation above (do not use NgModule)

That new module should declare and export the components created in Step 3

@CustomModule({
  declarations: [    Component1, Component2  ], 
  exports: [  Component1, Component2],
  bootstrap: [AppComponent]
})
export class InheritedModule extends CoreModule
{
}

Step 5

Import InheritedModule in the child app.

What the custom module function will do is merge annotations of the 2 modules, and replace CoreModule's components by InheritedModule's components when they have the same name

Question #2

I guess I'll have to replace bits of html templates with tiny components whenever I want to override part of the html from the core app. I'll leave the answer unaccepted for now in case somebody gets a better idea

like image 103
David Avatar answered Oct 04 '22 01:10

David