Guide to embedding one Angular application into another Angular application

I am looking to integrate two angular applications, A and B. Specifically, I want to display the entire application A within a tab in application B. How can I accomplish this task effectively?

I would greatly appreciate any guidance on how to achieve this functionality. Is there a special tag in Angular that would facilitate this integration seamlessly?

Answer №1

If you're facing a problem and need a solution, one approach could be to create the specific tag you require yourself. I successfully integrated Angular application A into Angular application B using a method known as web components or Angular elements. For more details, you can refer to resources like this article.

In the process, a tag called shiny-app-a is defined within application A, which is later imported and utilized in application B by referencing its JavaScript files.

The setup was tested in the following environment:

  • Angular CLI: 11.0.2
  • Node: 12.16.1
  • Operating System: win32 x64

To implement this integration, follow these steps:

1. Setting up Application A

Ensure that the package @angular/elements is also installed for this application.

1.1. Initializing Application A

$ ng new App-A
$ cd  App-A
$ ng add @angular/elements

1.2. Modifying app.modules.ts to define the web component/element and assign the tag shiny-app-a

My app.modules.ts file includes the following code:

import { BrowserModule } from '@angular/platform-browser';
// Add Injector
import { Injector, NgModule } from '@angular/core';
// Import createCustomElement
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
  AppComponent
  ],
  imports: [
  BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {

  constructor(private injector: Injector){}

  ngDoBootstrap(){
    const el = createCustomElement(AppComponent, {injector:this.injector});
    // Define the new tag shiny-app-a here
    customElements.define('shiny-app-a', el);
  }
}

1.3. Building the Project

$ ng build --prod --output-hashing none

This command generates various files including runtime.js, main.js, and polyfills.js, located in [...]\App-A\dist\App-A folder.

1.4. Testing the Application

Run

$ ng serve

You should now see your newly created Application A in the browser.

2. Setting up Application B

Note: You do not need @angular/elements package for this application.

2.1. Initialization of Application B

$ ng new App-B

2.2. Moving Files from Application A to a Shared Folder accessible by Application B

In this example, I used [...]/src/assets folder for this purpose.

$ cd App-B/src/assets/

Next, copy the JavaScript files from Application A to this folder, such as:

  • [...]/App-A/dist/App-A/main.js
  • [...]/App-A/dist/App-A/polyfills.js
  • [...]/App-A/dist/App-A/runtime.js

2.3. Adapting Application B's Source Code to utilize the tag defined earlier

2.3.1 Making custom elements available in Application B in app.module.ts

Include CUSTOM_ELEMENTS_SCHEMA when setting up Application B. Here's an excerpt of my app.modules.ts:

import { BrowserModule } from '@angular/platform-browser';
// Import CUSTOM_ELEMENTS_SCHEMA
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA], // Add schemas
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
2.3.2 Loading External JavaScript in app.component.ts

The JavaScript files can be loaded from any source. In this case, they are fetched during OnInit() from [...]/assets folder. Below is how my app.component.ts file looks:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'App-B';

  ngOnInit() {
    this.loadScript('/assets/runtime.js');
    this.loadScript('/assets/main.js');
    this.loadScript('/assets/polyfills.js');
  }

  public loadScript(url: string) {
    const body = <HTMLDivElement> document.body;
    const script = document.createElement('script');
    script.innerHTML = '';
    script.src = url;
    script.async = false;
    script.defer = true;
    body.appendChild(script);
  }
}
2.3.3 Implementing the Tag in app.component.html

Replace the existing content in app.component.html with just:

<shiny-app-a></shiny-app-a>

2.4. Testing the Integration

Run

$ ng serve

Now, you should be able to view Application A seamlessly embedded within Application B in the browser.

Answer №2

If you're looking to implement MICRO front ends, consider developing Application A as an Angular custom element using Angular Elements (a type of web component). The end result will be a script that can be loaded into Application B. Simply insert the specified selector from when you created the custom element in Micro App B wherever you want to display App A.

To learn more about Micro Front Ends and Angular Elements, check out this resource.

Avoid using iframes, as they can be quite challenging to manage. To expand your understanding, take some time to explore well-written blogs on implementing Micro Front Ends with Angular.

Answer №3

According to Akshay's suggestion, one option is to utilize Angular Elements to showcase your application A as a custom element that can be utilized in application B.

Specifically in your situation, the goal is to expose your AppComponent as a custom element.

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

Having trouble launching myapp on the Android Studio emulator for Ionic 3

My current project involves using Ionic with Cordova to develop an app without any visible errors in the CLI. I am also utilizing Android Studio to emulate the app. In addition, I am relying on the Chrome inspect feature to monitor my app's behavior ...

What are some effective ways to manage repetitive HTML elements like headers and footers in Angular 4?

Within my Angular web project, I find myself using a variety of different headers on multiple pages. Is there a way to streamline this process by coding the header and footer once and having them automatically included in one or more pages? I am looking ...

Issue encountered when trying to redirect after user creation on the backend

To persist a user, I use this method inside form-registrar-usuario.component: registrarUsuario(){ const role = this.route.snapshot.params["role"] if(role == "Proponedor"){ this.autorizacionService.registrarUsuario( role, thi ...

Guide to implementing a universal animated background with Angular components

I'm having trouble figuring out why, but every time I attempt to use a specific code (for example: https://codepen.io/plavookac/pen/QMwObb), when applying it to my index.html file (the main one), it ends up displaying on top of my content and makes ev ...

Tips for transforming Http into HttpClient in Angular 5 (or higher than 4.3)

I have successfully implemented code using Http and now I am looking to upgrade it to use the latest HttpClient. So far, I have taken the following steps: In App.module.ts: imported { HttpClientModule } from "@angular/common/http"; Added HttpClientModul ...

When trying to use the exported Ionic 3 class in TypeScript, the error "Cannot find name 'ClassName'" occurs

When working on my Ionic 3 Application, I encountered an error stating "Cannot find name" when trying to use certain plugins. I initially imported the plugin like this: import { AndroidPermissions } from '@ionic-native/android-permissions'; and ...

Distinguishing keyboard and mouse events while focusing in React app

I have been working on implementing keyboard navigation focus outline for accessibility. The pseudo class :focus-visible works well on all elements except for input elements like text or textarea. It seems that inputs always have this pseudo class active s ...

Discover the Magic of Angular 8 and Bootstrap 4 Tooltips

I'm trying to implement tooltips from Bootstrap 4 into my web application. According to Bootstrap documentation, I should initialize the tooltips with the following code: $(function () { $('[data-toggle="tooltip"]').tooltip() }) (Implement ...

fill the designated column in accordance with the specific criteria

Is there a method to automatically fill in a specific column based on certain conditions? I am looking to populate the column labeled [Last] when the column index is 1 and the corresponding name is [First]. import {Component, OnInit} from '@angular ...

The Angular Material Progress spinner and Progress bar fail to display

Currently focused on Angular 4, I initiated a fresh project using the following command : ng new test-app Afterwards, I executed : npm install --save @angular/material @angular/cdk ng g c first app.module.ts import { BrowserModule } from '@angular ...

Is there a way to resolve the issue of retrieving the processed value directly in NestJS's @OnEvent function?

Due to excessive logic in the API and its slow performance, I have resorted to handling some of the logic with @OnEvent. The problem arises when the frontend runs the @GET API immediately after this API, potentially without waiting for @OnEvent to update. ...

Discovering the quantity of items with a specific value in Angular 8

I'm attempting to determine the number of objects with a status value of 'Served', which should yield 2. I'm unsure about the method I should use to achieve this. Any suggestions on which method would be best? {full_name: 'Jenny&a ...

Filtering a key-value pair from an array of objects using Typescript

I am working with an array of objects containing elements such as position, name, and weight. const elements = [{ position: 3, name: "Lithium", weight: 6.941, ... },{ position: 5, name: "Boron", weight: 10.811, ... }, { position: 6, name: "Carbon", weight: ...

Exploring the power of TypeScript strictNullChecks with array manipulation

My understanding of Typescript's behavior with the compiler option strictNullChecks enabled is not yet complete. It appears that in some cases, Typescript (version 2.4.1) recognizes an item in a string[] as a string, while other times it does not: in ...

What are the best strategies to troubleshoot issues during NPM Install?

I keep encountering errors during the npm install process, but everything works fine when I use npm install --force in my local environment. However, the issues persist during the repository build as my .yaml file script contains "npm install". Can anyone ...

Utilizing npm to execute scripts stored in a dedicated file

I am currently working on an Angular project that consists of multiple libraries. The project follows a plugin architecture where the goal is to build and serve each plugin on separate servers. As the number of plugins increase, my build:plugins script is ...

To avoid TS2556 error in TypeScript, make sure that a spread argument is either in a tuple type or is passed to a rest parameter, especially when using

So I'm working with this function: export default function getObjectFromTwoArrays(keyArr: Array<any>, valueArr: Array<any>) { // Beginning point: // [key1,key2,key3], // [value1,value2,value3] // // End point: { // key1: val ...

Is there a method to define an 'internal' property within a TypeScript type?

I created a custom 'library' in Angular and TypeScript. This library is distributed as a *.ts package within other Angular workspaces. Within this library, I have an exported class that contains various properties. One specific property in thi ...

How can I use Angular to download the HTML content of a component when a button is clicked?

Is there a way to generate and download an HTML report directly from a dialog box in Angular 13.2.5 without redirecting the user to a separate page? The dialog box collects user input, and I want a button labeled "Generate" at the bottom of the dialog box ...

The method Office.context.mailbox.item.internetHeaders.setAsync has not been configured

I am integrating the Microsoft Office API into Outlook. I'm attempting to add an extra x-header to my email in the composer scope for later identification. To achieve this, I referred to the following documentation: https://learn.microsoft.com/en-us/j ...