Issue encountered while utilizing an AngularJS component within an Angular application: "Error: Attempting to access the AngularJS injector before its initialization."

I'm currently diving into Angular's upgrade guide in order to master the art of embedding AngularJS components within an Angular application. I've set up a basic Angular app using the Angular CLI and included a straightforward AngularJS module as a dependency.

After executing ng serve, the app compiles seamlessly without any errors. However, during runtime, I encounter the following message in the console:

Error: Trying to get the AngularJS injector before it being set.

What is causing this issue, and what steps can I take to prevent it? I've followed the guidelines outlined in the upgrade guide without deviation.

This is how I am upgrading my AngularJS component within the Angular app:

// example.directive.ts
import { Directive, ElementRef, Injector } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';

// Importing the npm module containing the AngularJS component
import { MyComponent } from '@my-company/module-test';

@Directive({
    selector: 'my-upgraded-component'
})
export class ExampleDirective extends UpgradeComponent {
    constructor(elementRef: ElementRef, injector: Injector) {

        // The .injectionName property represents the component's selector string; in this case, "my-component".
        super(MyComponent.injectionName, elementRef, injector);
    }
}

Additionally, here's my app.module.ts:

// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UpgradeModule } from '@angular/upgrade/static';
import { ExampleDirective } from './example.directive';
import { myModuleName } from '@my-company/module-test';

@NgModule({
    declarations: [AppComponent, ExampleDirective],
    imports: [BrowserModule, AppRoutingModule, UpgradeModule],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule {
    constructor(private upgrade: UpgradeModule) {}
    ngDoBootstrap() {
        this.upgrade.bootstrap(document.body, [myModuleName], {
            strictDi: true
        });
    }
}

The Angular version I am utilizing is 5.2.0.

Answer №1

Dealing with a similar issue led me to find a solution. There are specific steps to be taken before initiating a hybrid Angular/angularjs application.

  1. Start by installing the UpgradeModule using npm install @angular/upgrade

  2. Next, wrap your "CompanyModule" (the module where all company components are registered) within a new angularjs module (e.g., Ng1Shared). If you do not have a module for your company components, you will need to create one. Downgrade AppComponent following the example below.

    const MyCompanyModule = angular
       .module('MyCompanyModule', [])
       .component('myComponent', MyComponent)
       .name;
    
    
    const Ng1Shared = angular
       .module('Ng1Shared', [MyCompanyModule])
       .directive('appRoot', downgradeComponent({ component: AppComponent }))
       .name; 
    
  3. Configure AppModule with essential imports (BrowserModule, CommonModule, UpgradeModule). Provide the angularjs' Injector to Angular, declare an "entryComponent," and remove the default bootstrap for AppComponent.

    @NgModule({
      imports: [BrowserModule, CommonModule, UpgradeModule], 
      declarations: [AppComponent], 
      providers: [{provide: '$scope', useExisting: '$rootScope'}], // REQUIRED
      entryComponents: [AppComponent], // ADD AN ENTRY COMPONENT 
      // bootstrap: [AppComponent] MUST BE REMOVED
    })
    
  4. Globalize angularjs with a function from UpgradeModule and manually bootstrap Angular using DoBootstrap method provided by @angular/core.

    export class AppModule implements DoBootstrap { 
      constructor(private upgrade: UpgradeModule) { }
    
      public ngDoBootstrap(app: any): void {
        setAngularJSGlobal(angular);
        this.upgrade.bootstrap(document.body, [Ng1Shared], { strictDi: false });
        app.bootstrap(AppComponent);
      }
    }
    
  5. Create a wrapper directive for every angularjs component and add it to AppModule's declaration array.

    @Directive({
        selector: 'my-component'
    })
    export class MyComponentWrapper extends UpgradeComponent {
        @Input() title: string;
    
        constructor(elementRef: ElementRef, injector: Injector) {
          super('myComponent', elementRef, injector);
        }
    }
    

I have demonstrated a simple example on stackblitz. In this example, I added angularjs MyCompanyModule to another angularjs module, named Ng1Module, showcasing successful property binding between angularjs and angular components.

This information may prove helpful in resolving related issues.

Answer №3

Consider including entryComponents in your AppModule as shown below:

...
@NgModule({
    declarations: [AppComponent, ExampleDirective],
    imports: [BrowserModule, AppRoutingModule, UpgradeModule],
    entryComponents: [
          AppComponent // Make sure to include this!!!
    ],
    providers: [],
    // bootstrap: [AppComponent] // You can either delete or comment out this line 
})
...

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

Send both file and model data using AngularJS with FormData

When uploading an image using the file input type along with other user data, my model includes the User class: public class User { public int Id { get; set; } public string Name { get; set; } public int Rollno { get; set; } public byte[] ...

JQuery not properly validating inputs with required attributes after creation

I am currently developing a contact form that includes an "alternative address" <div id='alt'> with toggleable visibility. Inside this div, there is a required <input> field. I encountered an issue where toggling #alt twice (thus hidi ...

Unhandled error: 'this' is not defined within the subclass

My code snippet is causing an issue when run in Node v4.2.4: "use strict"; class Node { constructor() { } } class Person extends Node { constructor() { } } const fred = new Person(); Upon running the code, I encounter the following error mes ...

Saving a JSON array into separate JS variables using AJAX

I need to extract multiple values from a mySQL Query and store them in different JS Variables. Below is the AJAX code in my JS file: $.ajax({ async:false, url: "get_data.php", type: "POST", data: { d1: 'd ...

The functionality of activating a button is not functioning as expected in AngularJS framework

Next to the question I have linked here, I am exploring a different approach. As a beginner in AngularJS/Cordova/Ionic, my goal is to achieve different outcomes when the "Eingepasst" button is clicked, each with unique logic compared to "Gewonnen" or "Ver ...

Utilizing an Angular component for multiple purposes

For my Angular app, which is component-based and uses Angular version 1.5.5 with TypeScript, I have a header component that includes a country dropdown. This header component is used across multiple pages. However, when a country is selected from the dropd ...

The JSON data response is not being properly displayed on the div element

I am having trouble with the success function in my ajax call. The data is processed correctly in the view and the ajax call works fine, but for some reason, the data is not getting appended to the div. Here is my jQuery: $(document).ready(function() { ...

What is the method for altering the color of specific columns?

I am currently testing out my Amchart with this example. Check out the working demo on code pen My goal is to modify the color of the first four columns. While I am aware that colors can be changed by specifying them in the JSON file as a property calle ...

Ways to implement a placeholder height for images on a webpage with varying heights using HTML

I'm facing an issue with an image on my website that has a dynamic width and height as defined by the following CSS: .sm_item_image { width:100%; height:auto; max-width:400px; } The problem arises when the image takes some time to load, ...

"Replacing backslashes with forward slashes in JavaScript: A step-by-step guide

var string = "/\test\test1\test.jpg"; Looking for a way to swap out /\ with just \ using JavaScript? ...

Reorganizing JSON Information

Currently, I am dealing with a JSON file that contains multiple sets of data structured like this: {"name": ["Adelphi University"], "supp": ["Yes: E, WS"], "ed": ["\u00a0"], "online": ["$40"], "ea": ["12/1"], "mid": ["No"], "rd": ["Rolling"], "recs": ...

The onclick function is malfunctioning when attempting to use the Windows Phone app in Visual Studio 2015

web development <div class="align_center"> <div class="btn EmployeeloginBtn" **onclick="new Employee().connect()**>CONNECT</div> </div> Employee.js: var Employee = function() { var self = this; self.connect = fu ...

Display images next to each other with no need for a scroll bar

I'm currently developing a Roulette website and I am struggling to make the roulette animation function properly. I have an image for the roulette wheel, but I need the image to vanish after reaching a certain point and then loop around to the left. ...

Tips for preventing an AJAX response from populating a select dropdown

https://i.sstatic.net/gA1VE.gif In the example above, there is a placeholder (an option without value) that says something like Select Subcategory. When I change the category value, the subcategories are displayed. But what I want is for the subcategory ...

A mock or spy must be used for the jest function

I'm having an issue with the last expectation not being called in a test I'm writing to test the actions within my application. const pushData = jest.fn(() => Promise.resolve()); test('anotherAsyncCall is fired to get more info', ( ...

When a React page is re-rendered using useEffect, it automatically scrolls back to the

Every time I utilize the <Tabs> component, the onChange method triggers the handleTabChange function. This leads to the component being called again and after repainting, the useEffect is triggered causing the page to scroll back to the top. How can ...

When decoding a JWT, it may return the value of "[object Object]"

Having some trouble decoding a JSON web token that's being sent to my REST API server. I can't seem to access the _id property within the web token. Below is the code I'm currently using: jwt.verify(token, process.env.TOKEN_SECRET, { comp ...

How can you remove the add button in React Material Table?

Within the material table, there is a feature that allows for the conditional hiding/disabling of action buttons. Is there a way to do the same for the Add button located at the top of the table? See screenshot below ...

Tips for scrolling to the bottom of newly added elements in jQuery

Having trouble figuring out how to automatically scroll to the bottom of elements that I've prepended in HTML. Below is the code I'm using to prepend my data: var id = '#posts'+(yy-2); $.get('page-'+(yy-1) , function(data){ ...

Encountering issues while incorporating decimal.js in TypeScript

Incorporating decimal.js into my TypeScript project has proven to be challenging. When attempting to run the code snippet below, I encounter the following error message: Cannot assign to read only property 'constructor' of object '[object Ob ...