Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

I wanted to create a Class to share some common api data accross a sample app but I can't understand why one of the two below versions are not working:

Version 1 [./apiKeys.ts] - working

import {Injectable} from '@angular/core';
@Injectable()
export class SomeApi{
  key: string;
  url: string;
  constructor(){
    this.key = 'API_KEY';
    this.url = 'API_URL';
  }
}

Version 2 [./apiKeys.ts] - not working

import {Injectable} from '@angular/core';
@Injectable()
export class SomeApi{
  constructor(
    public key:string = 'API_KEY',
    public url:string = 'API_URL'
  ){}
}

I will then pass it as a provider at bootstrap

./main.ts

import {SomeApi} from './apiKeys.ts'
bootstrap(AppComponent, [SomeApi])

But at startup I am getting the following error (considering version 2):

ORIGINAL EXCEPTION: No provider for String! (SomeApi -> String)

Why is version 2 not working? Thanks


EDIT

After the suggestions from Günter Zöchbauer I had a look at some resources and found what I think is the best solution for my situation, here is what I did:

./apiKeys.ts

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

export interface AppConfig{
  key: string;
  url: string;
}

export const DI_CONFIG: AppConfig = {
  key: 'AIzaSyAjC3U-CbKYm_4sYV90XqJ_Upe8ID9jlxk',
  url: 'https://www.googleapis.com/youtube/v3/search'
}

export let APP_CONFIG = new OpaqueToken('app.config');

./main.ts

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

import { AppComponent } from './app.component';
import {DI_CONFIG, APP_CONFIG} from './apiKeys';

bootstrap(AppComponent, [{ provide: APP_CONFIG, useValue: DI_CONFIG }]);

./apiService.ts

import {Injectable, Inject} from '@angular/core';
import {APP_CONFIG, AppConfig} from './apiKeys';

@Injectable()
export class ApiService{
  constructor(
    @Inject(APP_CONFIG) private config: AppConfig
  ){}
  // i can then use it with this.config.url - this.config.key
}

Sources:

share|improve this question
up vote 0 down vote accepted

If you don't add @Inject(...) to constructor parameters, Angulars DI uses the parameter type as key to look up providers.

In your case this is string for both parameters which is ambiguous.
You also didn't register providers at all.

You need to provide with an artificial key like

bootstrap(AppComponent, [
  {provide: 'myKey', useValue: 'A'}, 
  {provide: 'myUrl', useValue: 'B'}, 
  SomeApi
])
import {Injectable} from '@angular/core';
@Injectable()
export class SomeApi{
  key: string;
  url: string;
  constructor(){
    @Inject('myKey') this.key = 'API_KEY';
    @Inject('myUrl') this.url = 'API_URL';
  }
}

If you don't want to provide these values, you can use @Optional() like

import {Injectable} from '@angular/core';
@Injectable()
export class SomeApi{
  @Optional() key: string;
  @Optional() url: string;
  constructor(){
    this.key = 'API_KEY';
    this.url = 'API_URL';
  }
}

then DI only injects if it finds a matching provider.

share|improve this answer
    
Thanks for your precious help. I have edited my question since I have added what I think could be another approach since those dependencies I wanted to inject were just strings and using a class with string parameters was just a "workaround". – crash Jul 19 at 9:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.