question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Error: No provider for InjectionToken mat-autocomplete-scroll-strategy

See original GitHub issue

I upgraded my project from Angular 8 to 9 and refactored my code to take advantage of the ability to lazy load components. For most of my components this works great, but I have one that is throwing an error and I need help resolving the issue.

Here is my component code followed by the error. The module is defined in the same file as the component.

import { Component, OnInit, OnDestroy, NgModule } from '@angular/core';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { switchMap, debounceTime, tap, filter } from 'rxjs/operators';
import { MatFormFieldModule, MatInputModule, MatAutocompleteModule, MatButtonModule, MatProgressSpinnerModule, MatIconModule, MatDialogModule } from '@angular/material';
 
import { SearchService } from './search.service';
import { SuggestResult } from './suggest-result';
import { CommonModule } from '@angular/common';
import { HttpClientModule } from '@angular/common/http';
import { SharedModule } from 'src/app/shared/shared.module';
 
@Component({
    selector: 'app-search',
    templateUrl: './search.component.html',
    styleUrls: ['./search.component.scss'],
    providers: [ FormBuilder]
})
export class SearchComponent implements OnInit, OnDestroy {
 
//code removed
 
}
 
@NgModule({
    imports: [
        CommonModule,
        HttpClientModule,
        FormsModule,
        ReactiveFormsModule,
        MatFormFieldModule,
        MatInputModule,
        MatAutocompleteModule,
        MatButtonModule,
        MatProgressSpinnerModule,
        MatIconModule,
        SharedModule,
        MatDialogModule
    ],
    declarations: [SearchComponent]
})
export class SearchModule { }
<div>
    <div class="form-container">
        <form [formGroup]='resultsForm'>
            <mat-form-field [class.mat-form-field-invalid]="!formFieldValid">
                <input matInput placeholder="Search term" type="search" [matAutocomplete]="SearchAuto" formControlName='SearchUserInput'>
            </mat-form-field>

            <div *ngIf="!formFieldValid" class="error-msg"> {{ errorMessage }} </div>
            
            <mat-autocomplete #SearchAuto="matAutocomplete" [displayWith]="getSelectedText"
                (optionSelected)='onItemSelected($event.option.value)'>
                <mat-option *ngIf="isLoading" class="is-loading">
                    <mat-spinner mode="indeterminate" diameter="25"></mat-spinner>
                </mat-option>

                <ng-container *ngIf="!isLoading">
                    <mat-option *ngFor="let result of filteredResults" [value]="result">
                        <span>{{ result.name }}</span>
                    </mat-option>
                </ng-container>
            </mat-autocomplete>
        </form>
        <mat-icon>search</mat-icon>
        <button mat-button *ngIf="isNotEmpty()" matSuffix mat-icon-button aria-label="Clear" (click)="clearSearch()">
            <mat-icon>close</mat-icon>
        </button>
    </div>
</div>

The error:

null: Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[InjectionToken mat-autocomplete-scroll-strategy -> InjectionToken mat-autocomplete-scroll-strategy -> InjectionToken mat-autocomplete-scroll-strategy]: NullInjectorError: No provider for InjectionToken mat-autocomplete-scroll-strategy! ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/NullInjector.prototype.get@http://localhost:4200/vendor.js:37066:25 ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/R3Injector.prototype.get@http://localhost:4200/vendor.js:47422:33 ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/R3Injector.prototype.get@http://localhost:4200/vendor.js:47422:33 ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/R3Injector.prototype.get@http://localhost:4200/vendor.js:47422:33 ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/NgModuleRef$1.prototype.get@http://localhost:4200/vendor.js:60382:33 get@http://localhost:4200/vendor.js:58703:35 getOrCreateInjectable@http://localhost:4200/vendor.js:39763:39 ɵɵdirectiveInject@http://localhost:4200/vendor.js:50290:12 MatAutocompleteTrigger_Factory@http://localhost:4200/vendor.js:76965:788 getNodeInjectable@http://localhost:4200/vendor.js:39871:44 searchTokensOnInjector@http://localhost:4200/vendor.js:39807:16 getOrCreateInjectable@http://localhost:4200/vendor.js:39729:58 ɵɵdirectiveInject@http://localhost:4200/vendor.js:50290:12 ɵɵinject@http://localhost:4200/vendor.js:36956:57 factory@http://localhost:4200/vendor.js:47681:44 multiResolve@http://localhost:4200/vendor.js:55407:21 multiProvidersFactoryResolver@http://localhost:4200/vendor.js:55372:12 getNodeInjectable@http://localhost:4200/vendor.js:39871:44 searchTokensOnInjector@http://localhost:4200/vendor.js:39807:16 getOrCreateInjectable@http://localhost:4200/vendor.js:39729:58 ɵɵdirectiveInject@http://localhost:4200/vendor.js:50290:12 FormControlName_Factory@http://localhost:4200/vendor.js:74579:400 getNodeInjectable@http://localhost:4200/vendor.js:39871:44 searchTokensOnInjector@http://localhost:4200/vendor.js:39807:16 getOrCreateInjectable@http://localhost:4200/vendor.js:39729:58 ɵɵdirectiveInject@http://localhost:4200/vendor.js:50290:12 ɵɵinject@http://localhost:4200/vendor.js:36956:57 factory@http://localhost:4200/vendor.js:47681:44 getNodeInjectable@http://localhost:4200/vendor.js:39871:44 searchTokensOnInjector@http://localhost:4200/vendor.js:39807:16 getOrCreateInjectable@http://localhost:4200/vendor.js:39729:58 ɵɵdirectiveInject@http://localhost:4200/vendor.js:50290:12 MatInput_Factory@http://localhost:4200/vendor.js:99837:370 getNodeInjectable@http://localhost:4200/vendor.js:39871:44 instantiateAllDirectives@http://localhost:4200/vendor.js:44362:42 createDirectivesInstances@http://localhost:4200/vendor.js:43753:29 ɵɵelementStart@http://localhost:4200/vendor.js:50436:34 ɵɵelement@http://localhost:4200/vendor.js:50487:19 SearchComponent_Template@http://localhost:4200/search-search-search-component.js:190:56 executeTemplate@http://localhost:4200/vendor.js:43726:19 renderView@http://localhost:4200/vendor.js:43551:28 renderComponent@http://localhost:4200/vendor.js:44741:15 renderChildComponents@http://localhost:4200/vendor.js:43412:24 renderView@http://localhost:4200/vendor.js:43576:34 ./node_modules/@angular/core/ivy_ngcc/fesm5/core.js/ComponentFactory.prototype.create@http://localhost:4200/vendor.js:58804:23 createContainerRef/R3ViewContainerRef</ViewContainerRef.prototype.createComponent@http://localhost:4200/vendor.js:46481:53 ./src/app/dynamic-loader/dynamic-loader.service.ts/DynamicLoaderService.prototype.addComponentToContainer/obs<@http://localhost:4200/main.js:583:23 ./node_modules/zone.js/dist/zone.js/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2740:30 onInvoke@http://localhost:4200/vendor.js:63629:33 ./node_modules/zone.js/dist/zone.js/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invoke@http://localhost:4200/polyfills.js:2739:36 ./node_modules/zone.js/dist/zone.js/</Zone$1</Zone</Zone.prototype.run@http://localhost:4200/polyfills.js:2497:47 scheduleResolveOrReject/<@http://localhost:4200/polyfills.js:3238:38 ./node_modules/zone.js/dist/zone.js/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2775:35 onInvokeTask@http://localhost:4200/vendor.js:63617:33 ./node_modules/zone.js/dist/zone.js/</Zone$1</ZoneDelegate</ZoneDelegate.prototype.invokeTask@http://localhost:4200/polyfills.js:2774:40 ./node_modules/zone.js/dist/zone.js/</Zone$1</Zone</Zone.prototype.runTask@http://localhost:4200/polyfills.js:2542:51 drainMicroTaskQueue@http://localhost:4200/polyfills.js:2955:39

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:17
  • Comments:25 (6 by maintainers)

github_iconTop GitHub Comments

18reactions
JoostKcommented, Mar 20, 2020

It does not look like there’s a bug here, but there is a catch and ergonomic issue to this situation.

The root of the problem is that the SearchModule that imports MatAutocompleteModule is never instantiated, as it’s not imported from AppModule. This results in none of the (transitively) provided providers being available.

So as a solution, we need to ensure that the SearchModule is used when creating the SearchComponent. To achieve this, you’d currently need to inject the Compiler and use its compileModuleSync method to obtain an NgModuleFactory for the imported SearchModule class.

Importing the compiler seems counter-intuitive, as we don’t need JIT compilation here. Fortunately in Ivy, this comes at no additional costs: there is no need to use platformBrowserDynamic to pull in the whole compiler. This approach is actually exactly what the Router uses under the covers for its loadChildren support.

Given the NgModuleFactory, we can use its componentFactoryResolver to be able to create the component factory for SearchComponent in the context of the SearchModule instead of AppModule. Therefore, the injected ComponentFactoryResolver is no longer needed, as that is bound to AppModule.

import { Component, VERSION, ComponentFactoryResolver, ViewContainerRef, ViewChild, NgModuleRef, Compiler } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  
  constructor(private compiler: Compiler) {}

  @ViewChild("container", { read: ViewContainerRef })
  container: ViewContainerRef;

  loadsearch() {
    import("./search/search.component").then(c => {
      console.log(c);

      const ngModuleFactory = this.compiler.compileModuleSync(c.SearchModule);
      const ngModule = ngModuleFactory.create(this.container.injector);

      const factory = ngModule.componentFactoryResolver.resolveComponentFactory(c.SearchComponent);

      console.log(factory);

      this.container.createComponent(factory);
    });
  }
}

The ergonomics are not ideal here, as all APIs have been designed around the “factory” concept that was needed with ViewEngine (the renderer before Ivy).

I’m keeping this issue open for tracking this use-case, but I’m adjusting the severity label as you mentioned you started to take advantage of lazy loading which introduced the issue.

EDIT: Please bear in mind that the example above will create a new instance of SearchModule each time, which may not be desirable. Consider caching the ngModule somewhere (or even just factory in this case) but keep in mind that this instance is specific to a parent Injector, which is this.container.injector in this case.

6reactions
bollerdominikcommented, Mar 14, 2020

I am also having this exact issue when having a lazy loaded module with MatAutocomplete

Read more comments on GitHub >

github_iconTop Results From Across the Web

No provider for InjectionToken mat-autocomplete-scroll-strategy
Here is my component code followed by the error. The module is defined in the same file as the component. import { Component,...
Read more >
mat-autocomplete-scroll-strategy-error - CodeSandbox
VS Code's tsserver was deleted by another application such as a misbehaving virus detection tool. Please reinstall VS Code. Manage Extension.
Read more >
Autocomplete | Angular Material
Injection token that determines the scroll handling while the autocomplete panel is open. const MAT_AUTOCOMPLETE_SCROLL_STRATEGY: InjectionToken<() => ...
Read more >
nullinjectorerror: no provider for matdialogref!, no provider for ...
Currently we have the `MAT_DIALOG_SCROLL_STRATEGY` token which allows consumers to specify the scroll strategy for all dialogs, however there's no way do so...
Read more >
Scroll Strategy Block - StackBlitz
MatAutocompleteModule,. MatButtonModule,. MatButtonToggleModule,. MatCardModule,. MatCheckboxModule,. MatChipsModule,. MatDatepickerModule,.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found