7

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 which are used explicitly 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 overridden 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

1 Answer 1

3

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

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks David, I'm looking for exactly the same. Did you find a more "officially" supported solution in the meantime? Currently we've two open issues with Angular 4, where overrides of modules/components, etc. is the first one and second is lazy loading of beforehand unknown modules, like wix/angular-widget does for Angular 1.
I've setup a system which automatically copies the coremodule files when they are modified into the child modules. By default, the child modules use that copy, but that can overwrite it if needed
Hmmm, copying files, etc. isn't really what I'd in mind by more "officially". I'm currently playing with import(), which can dynamically import anything, just figuring out the best ways to make use of it, but Angular seems not be ready for prime time to load whole modules this way, but we'll see. :) It's introduced here but better explained with Angular in Angular Tips: Dynamic Module Imports with the Angular CLI.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.