Alabede Abdulmalik
Alabede Abdulmalik

Reputation: 93

.NetCore 2 Angular 5 - Error: StaticInjectorError(AppModule)[BASE_URL]:

I get this error when i am trying to navigate to a WebApi Controller. This error is what i get as soon as the page loads because the codes are situated in the constructor function.

core.js:1598 ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[BASE_URL]: 
  StaticInjectorError(Platform: core)[BASE_URL]: 
    NullInjectorError: No provider for BASE_URL!
Error: StaticInjectorError(AppModule)[BASE_URL]: 
  StaticInjectorError(Platform: core)[BASE_URL]: 
    NullInjectorError: No provider for BASE_URL!
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:979)
    at resolveToken (core.js:1232)
    at tryResolveToken (core.js:1182)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
    at resolveToken (core.js:1232)
    at tryResolveToken (core.js:1182)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
    at resolveNgModuleDep (core.js:9217)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:9911)
    at resolveDep (core.js:10276)
    at NullInjector.push../node_modules/@angular/core/fesm5/core.js.NullInjector.get (core.js:979)
    at resolveToken (core.js:1232)
    at tryResolveToken (core.js:1182)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
    at resolveToken (core.js:1232)
    at tryResolveToken (core.js:1182)
    at StaticInjector.push../node_modules/@angular/core/fesm5/core.js.StaticInjector.get (core.js:1077)
    at resolveNgModuleDep (core.js:9217)
    at NgModuleRef_.push../node_modules/@angular/core/fesm5/core.js.NgModuleRef_.get (core.js:9911)
    at resolveDep (core.js:10276)
    at resolvePromise (zone.js:814)
    at resolvePromise (zone.js:771)
    at zone.js:873
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
    at Object.onInvokeTask (core.js:4053)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
    at drainMicroTaskQueue (zone.js:595)

login.component.ts

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

import { NgForm } from '@angular/forms';
import { Router, ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';

import { Candidates } from '/Solutions/Angular/ExamBuddy/Interfaces/Candidate';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})


export class LoginComponent  {
  candDetails: Candidates;

  constructor(private http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
    var url = baseUrl + '/api/Candidate/ExamDetails/12345';
    this.http.get<Candidates>(url).subscribe(result => { this.candDetails = result; }, error => console.error(error));
  }

This is also my app.module.ts code.

app.module.ts

    import { BrowserModule } from '@angular/platform-browser';

    import { NgModule } from '@angular/core';
    import { HttpClientModule } from '@angular/common/http';
    import { FormsModule } from '@angular/forms';
    import { AppComponent } from './app.component';
    import { ExamComponent } from './exam/exam.component';
    import { LoginComponent } from './login/login.component';
    // import { RouterModule } from '@angular/router';
    import { InstructionComponent } from './instruction/instruction.component';
    import { routes } from './app.route';


    @NgModule({
      declarations: [
        AppComponent,
        ExamComponent,
        LoginComponent,
        InstructionComponent,

      ],
      imports: [
        BrowserModule,
        HttpClientModule,
        FormsModule,
        routes 
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }

i also have the WebApi controller which connects to the database and fetches the result in JSON format.

Upvotes: 2

Views: 8378

Answers (3)

James Wilkins
James Wilkins

Reputation: 7357

In my case I tried to enable Hot Module Replacement. The official instructions for HMR have this example for main.ts:

Update src/main.ts to use the file we just created:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

import { hmrBootstrap } from './hmr';

if (environment.production) {
  enableProdMode();
}

const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule);

if (environment.hmr) {
  if (module[ 'hot' ]) {
    hmrBootstrap(module, bootstrap);
  } else {
    console.error('HMR is not enabled for webpack-dev-server!');
    console.log('Are you using the --hmr flag for ng serve?');
  }
} else {
  bootstrap().catch(err => console.log(err));
}

(https://github.com/angular/angular-cli/wiki/stories-configure-hmr)

However, the Visual Studio 2017 ASP.Net Core Angular CLI template includes these lines:

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

platformBrowserDynamic(providers).bootstrapModule(AppModule)
  .catch(err => console.log(err));

Notice that the providers array is not being passed into the HMR main.ts example. The simple fix is to simply pass it in to platformBrowserDynamic. The corrected line then looks like this:

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

const bootstrap = () => platformBrowserDynamic(providers).bootstrapModule(AppModule);

Upvotes: 0

First: In main.ts, I have the following code, which refers to index.html

export function getBaseUrl() {
  return document.getElementsByTagName('base')[0].href;
}

const providers = [
  { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
];

platformBrowserDynamic(providers).bootstrapModule(AppModule)
  .catch(err => console.log(err));

Second: In our component (fetch-data.component.ts), we use the BASE_URL in the following way:

export class FetchDataComponent {
    public forecasts: WeatherForecast[];

    constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {
        http.get<WeatherForecast[]>(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
           this.forecasts = result;
        }, error => console.error(error));
    }
}

that's it.

Upvotes: 4

Markus Hennerbichler
Markus Hennerbichler

Reputation: 96

You are injecting a string value with the key BASE_URL in your LoginComponent, with the inject decorator: @Inject('BASE_URL') baseUrl: string. For this to work you need to provide a value for BASE_URL in your AppModule. But you didn't provide a vaule, this is what the error is telling you: NullInjectorError: No provider for BASE_URL!

In Angular 5 it is recommended to create InjectionToken e.g.

import { InjectionToken } from '@angular/core';
export const BASE_URL = new InjectionToken<string>('BASE_URL');

providing the value in your AppModule is done by defining a provider in your AppModule:

providers: [  { provide: BASE_URL , useValue: "http://example.com/api" }

you can then use this InjectionToken in your LoginComponent like this:

constructor(private http: HttpClient, @Inject(BASE_URL) baseUrl: string) {

Further informations regarding injection of values can be found in the offical documentation: https://angular.io/guide/dependency-injection#dependency-injection-tokens

Upvotes: 4

Related Questions