简体   繁体   中英

Angular2 Component factory for extended components

I'm trying to build a component based app, which most of the code should be reusable, also with some other stylesheets etc.

The goal is, that we have some core components, which we can use for other projects too. They should be extendable, so you can customize the style, functionality, etc.

Now I'm trying to find a solution for my problem: I'd like to have a mechanism, that when I extend a component, the application already loads the extended component and not the super component. I know I could create a new component for the extended one, but so I have to adapt the code in the whole application.

A little example: I have a component EditableList, with a basic styling and logic and a round button component (ListButton). The EditableList component is used as it is in the App1.

Now in the App2, I'd like to extend/overwrite the ListButton component, that it is no longer round one, but a rectangular one (RectListButton). However when I extend the component, I have to create a new component (for example RectListButton), copy the code of EditableList into a new component, change the ListButton to RectListButton(in the EditableList component) and use that new EditableList2 component in my App2.

Is there any possibility to have a factory which recognizes, that I have extended that component and loads the extended component instead the base component? That means for my example, I just have to extend the ListButton and the EditableList component automatically detects, that the ListButton got overwritten and loads my extended RectListButton in (or maybe ListButtonExtended for a better naming). Thus, I can reuse the EditableList component, without copying and modifying it.

Thank you very much!

Regards Fabian

Here is a solution that worked for me

Step 1

Place your core components in a core module (CoreModule in app 1, containing EditableList and ListButton components).

Step 2

Somewhere, declare the following CustoModule fonction

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 app 2, create a new ListButton component (the rectangular one in your case) but call it ListButton (important for the next steps). It has to have the same selector as the core module's ListButton

Step 4

Then have some App2ComponentModule module in app2 that extends CoreModule. Declare that module with the CustomModule annotation above (do not use NgModule)

That new module should declare and export ListButton

@CustomModule({
  declarations: [    ListButton  ], //ListButton from app2
  exports: [  ListButton],//ListButton from app2
  bootstrap: [AppComponent]
})
export class App2ComponentModule extends CoreModule
{
}

Step 5

In app 2, import App2ComponentModule from the app2 main module.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM