Customizing Components in Angular 2/4 by Overriding Them from a Different Module

Currently, I am utilizing Angular 4.3 and TypeScript 2.2 for my project.

My goal is to develop multiple websites by reusing the same codebase. Although most of the websites will have similar structures, some may require different logic or templates.

My plan involves creating a core Module that consists mainly of components. The idea is for applications to utilize this module as a foundation and make necessary overrides:

  • the styles
  • the templates (completely replacing the template or modifying some parts)
  1. How can I replace the components used in the core module?

Currently, I can only replace the components explicitly used in the routing. However, I am unable to override child components directly called in the templates of the Core module. Should I dynamically inject these components?

  1. Is it possible to override only a section of the parent template when inheriting a component?

It seems that each template section requiring an override would need to be converted into a component in the core module (leading back to question #1 to use the inherited component in the child apps).

Thank you

Answer №1

Query #1

Here's a successful approach I implemented:

Stage 1

I organized all essential components in a core module within a core application.

Stage 2

I defined the CustomModule function in the core app as follows:

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 (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)
        {  
          annotations[key] = parentAnnotation[key];
        }
      }
    });

    let metadata = new NgModule(annotations);

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

Stage 3

In a separate application, I established a module called InheritedModule and developed components that inherit from those in the CoreModule. The inherited component should have identical names and selectors as the parent component.

Stage 4

I ensured that InheritedModule inherited from the CoreModule and was declared with the CustomModule annotation mentioned above (not using NgModule).

This new module should declare and export the components created in Stage 3.

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

Stage 5

Import InheritedModule into the child app.

The custom module function will merge annotations of the two modules and substitute CoreModule components with InheritedModule components when they share the same name.

Query #2

If I need to override parts of the HTML from the core app, I may have to replace sections with small components. I will keep the answer pending to explore better suggestions.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Employing ngModel in an option dropdown

I am having trouble passing an attribute from an API call to a submit function. I suspect it might have something to do with either the option select or how the input is being formatted. Encountering the error Error: No value accessor for form control wit ...

Is it possible to utilize an Angular2 service with the DOM addEventListener?

Issue: I am encountering an problem where the service appears to be empty when trying to call it within an addEventListener. Html: <div id="_file0"> Service: @Injectable() export class FilesService { constructor(private http : Http) { } } Co ...

Updating components in Angular4 when route changesHow to update components on route

How can I ensure my component updates when the route changes? Here is the code for my component : import { Component, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { ListService } from '.. ...

Attribute specified does not belong to type 'DetailedHTMLProps<ButtonHTMLAttributes

I am working on creating a reusable 'button' component and I would like to include a href attribute so that when the button is clicked, it navigates to another page. An Issue Occurred: The following error was encountered: 'The type '{ ...

Could you provide insight into the reason behind debounce being used for this specific binding?

function debounce(fn, delay) { var timer return function () { var context = this var args = arguments clearTimeout(timer) timer = setTimeout(function () { fn.apply(context, args) }, delay) ...

Problem with Ionic 2 local storage: struggling to store retrieved value in a variable

Struggling to assign the retrieved value from a .get function to a variable declared outside of it. var dt; //fetching data this.local.get('didTutorial').then((value) => { alert(value); dt = value; }) console.log("Local Storage value: " ...

Error 16 occurred when attempting to ngUpgrade two different versions of Highcharts

After successfully upgrading my app to use ngUpgrade, I encountered an issue while trying to incorporate Highcharts. In the original version of the app, there was an older version of Highcharts designed for AngularJS. However, in the new hybrid app using ...

Ways to center a spinner on the screen using CSS during loading

Upon loading the page, my spinner appears in the center of the screen after a second. However, in the initial frame of the page, it is not centered but positioned on the top-left corner instead. How can I ensure that my spinner starts off centered from the ...

What is the process of converting a `typeorm` model into a GraphQL payload?

In my current project, I am developing a microservice application. One of the services is a Node.js service designed as the 'data service', utilizing nestjs, typeorm, and type-graphql models. The data service integrates the https://github.com/nes ...

Convert C# delegate into TypeScript

Sample C# code snippet: enum myEnum { aa = 0, bb, cc, } public delegate void MyDelegate(myEnum _myEnum, params object[] _params); public Dictionary<myEnum , MyDelegate> dicMyDelegate = new Dictionary<myEnum , MyDelegate>(); publi ...

It takes two clicks for the text to change on the button in Angular

As a newcomer to angular, I am working on a quiz application where I've encountered an issue. When I click a button, it requires two clicks to function properly. The first click works fine, but subsequent clicks on the next and back buttons need to be ...

Is it possible for Typescript and Next.js to import a different project's *source code* only from the module's root directory?

Issue with Sharing React Components between Closed and Open Source Next.js Projects I am facing a challenge in my development setup involving two Next.js projects, one closed source (Project A) and the other open source (Project B). In Project A, which is ...

Is there a way to determine the most recent Typescript target compatibility for every Node version?

When using any version of Node, how can I identify the appropriate Typescript Compiler Option for target that offers the most functionality? I want to eliminate any guesswork. Specify the ECMAScript target version as: "ES3" (default), "ES5", "ES6"/"ES20 ...

What is the best method for setting up a worldwide list of approved URLs?

Looking to incorporate a universal whitelist feature for secure URLs in bypassing resource URLs within Angular 2, inspired by the functionality offered in AngularJS via the $sceDelegateProvider as explained here I've attempted to consult the Angular ...

I'm interested in learning how to implement dynamic routes in Nexy.js using TypeScript. How can I

I have a folder structure set up like this: https://i.stack.imgur.com/qhnaP.png [postId].ts import { useRouter } from 'next/router' const Post = () => { const router = useRouter() const { pid } = router.query return <p>Post: {p ...

Combining Bazel, Angular, and SocketIO Led to: Unforeseen Error - XMLHttpRequest Not Recognized as Constructor

I am looking to integrate ngx-socket-io into my Angular application. I utilize Bazel for running my Angular dev-server. Unfortunately, it seems that ngx-socket-io does not function properly with the ts_devserver by default. Upon checking the browser consol ...

Implement a HTTP interceptor in a component

Recently, I developed an HTTP interceptor as shown below: @Injectable() export class NoopInterceptor implements HttpInterceptor { public my_status: boolean = true; private _statusChange: Subject<boolean> = new Subject<boolean>(); ...

Tips for sending properties to a child component in a React Native project using TypeScript

Here is the setup in my parent component: const [OTPNotify, setOTPNotify] = useState("flex"); const closeOTPNotify = () => { setOTPNotify("none"); } <OTPRibbonComponent onCancel={closeOTPNotify} display={OTPNotify}/> Now, ...

What is the most effective method for incorporating JWT authentication in Angular (Client Side) without relying on Local Storage?

I recently encountered a challenge while attempting to implement JWT token for Angular Authentication on the client side. I have been searching for alternative methods of storing the jwt token beside local storage, but haven't found a suitable impleme ...

Unit testing in Angular 2+ involves testing a directive that has been provided with an injected window object

Currently, I am faced with the challenge of creating a test for a directive that requires a window object to be passed into its constructor. This is the code snippet for the directive: import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit ...