Angular 6 Passing injectables array to providers in app.module.ts causes: "Error in Cannot read property 'length' of undefined"

Viewed 691

I have the following array with injectables that are connected from services:

import { YouTubeSearchService,
     YOUTUBE_API_KEY,
     YOUTUBE_API_URL } from './you-tube.service';

export const youTubeSearchInjectables: Array<any> = [
    { provide: YouTubeSearchService, useClass: YouTubeSearchService },
    { provide: YOUTUBE_API_KEY, useClass: YOUTUBE_API_KEY },
    { provide: YOUTUBE_API_URL, useClass: YOUTUBE_API_URL }
];

And I am trying to pass it to providers in app.module.ts:

/*other imports*/
import { youTubeSearchInjectables } from './search-result/you-tube-search.injectables';

@NgModule({
  declarations: [
    AppComponent,
    SimpleHttpComponent,
    SearchResultComponent,
    SearchBoxComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpClientModule
  ],
  providers: [youTubeSearchInjectables],
  bootstrap: [AppComponent]
})
export class AppModule { }

However, I get "ERROR in Cannot read property 'length' of undefined" (Just one line, nothing else).

I believe the reason has, most probably, something to do with version of Angular. I am using 6 and the book project is written in version 5. However, Angular documentation on Dependency Injection says that the book-way is the right way... So I am a bit confused. Or maybe I am simply missing something.

I actually tried manually adding each injectable into app.module, but got the same error.

Any help would be appreciated

EDIT: tried "providedIn: 'root'," in accordance with ng6 update, but that didn't help.

Just in case - the injectable class:

/*imports*/

export const YOUTUBE_API_KEY = 'keykeykey';
export const YOUTUBE_API_URL = 'https://www.googleapis.com/youtube/v3/search';

@Injectable({
  providedIn: 'root',
})
export class YouTubeSearchService {
  constructor(
    private http: HttpClient,
    @Inject(YOUTUBE_API_KEY) private apiKey: string,
    @Inject(YOUTUBE_API_URL) private apiUrl: string
  ) { }

  search(query: string): Observable<SearchResult[]> {
    // logic
  }
}
1 Answers

I see two problems with your code. The first is that you are using an array inside of an array to define your providers. Either reference the youTubeSearchInjectables variable straight or use the spread operator to concatenate your exported providers into the providers array of the module.

The second issue, which you will not notice until the first issue is solved, is that you should use useValue instead of useClass for YOUTUBE_API_KEY and YOUTUBE_API_URL since these two are not classes but simple string values.

const youTubeSearchInjectables: Array<any> = [
  { provide: YouTubeSearchService, useClass: YouTubeSearchService },
  { provide: YOUTUBE_API_KEY, useValue: YOUTUBE_API_KEY },
  { provide: YOUTUBE_API_URL, useValue: YOUTUBE_API_URL }
];

@NgModule({
  providers: [
    ...youTubeSearchInjectables
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }
Related