1

I am trying to configuring Angular-Slickgrid in Angular version 18.0.0 by following Angular-Slickgrid documentation. But I am getting an error in chrome browser saying

NullInjectorError: No provider for _ContainerService!

Here is my angular version 18 source code imports statements and component decorator etc.

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { AngularSlickgridModule,Column, GridOption } from 'angular-slickgrid';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet,AngularSlickgridModule],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})

Any clue what's going wrong, since in Angular 18, the App Modules have been removed so every dependencies I have installed are in the component itself.

1 Answer 1

3

Steps to be followed!

First install bootstrap and angular-slickgrid

npm install angular-slickgrid
npm install bootstrap

In the angular.json add the styles to the array!

        ...
        "styles": [
          ...
          "../node_modules/bootstrap/dist/css/bootstrap.css",
          "node_modules/@slickgrid-universal/common/dist/styles/css/slickgrid-theme-bootstrap.css"
          ...
        ],
        "scripts": [],
        ...

STANDALONE METHOD:

If your app is using standalone style, go to app.config.ts

import {
  ApplicationConfig,
  importProvidersFrom,
  provideZoneChangeDetection,
} from '@angular/core';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';
import { AngularSlickgridModule } from 'angular-slickgrid';

export const appConfig: ApplicationConfig = {
  providers: [
    provideZoneChangeDetection({ eventCoalescing: true }),
    provideRouter(routes),
    importProvidersFrom(AngularSlickgridModule.forRoot()), // <- notice!
  ],
};

Then import the AngularSlickgridModule to the app.component.ts

import { RouterOutlet } from '@angular/router';
import { Component, OnDestroy, OnInit } from '@angular/core';
import {
  Column,
  GridOption,
  Formatters,
  AngularGridInstance,
  AngularSlickgridModule,
} from 'angular-slickgrid';

const NB_ITEMS = 995;

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, AngularSlickgridModule], // <- notice!
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {
    ...

Then you are good to go!

FULL CODE:

TS:

import { RouterOutlet } from '@angular/router';
import { Component, OnDestroy, OnInit } from '@angular/core';
import {
  Column,
  GridOption,
  Formatters,
  AngularGridInstance,
  AngularSlickgridModule,
} from 'angular-slickgrid';

const NB_ITEMS = 995;

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, AngularSlickgridModule],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {
  private _darkModeGrid1 = false;
  title = 'Example 1: Basic Grids';
  subTitle = `
    Basic Grids with fixed sizes (800 x 225) set by "gridHeight" &amp; "gridWidth"
    <ul>
      <li><a href="https://ghiscoding.gitbook.io/angular-slickgrid/getting-started/quick-start" target="_blank">Wiki HOWTO link</a></li>
    </ul>
  `;

  angularGrid1!: AngularGridInstance;
  columnDefinitions1: Column[] = [];
  columnDefinitions2: Column[] = [];
  gridOptions1!: GridOption;
  gridOptions2!: GridOption;
  dataset1!: any[];
  dataset2!: any[];

  ngOnInit(): void {
    this.prepareGrid();
  }

  ngOnDestroy() {
    // document.querySelector('.panel-wm-content')!.classList.remove('dark-mode');
    // document.querySelector<HTMLDivElement>('#demo-container')!.dataset.bsTheme =
    //   'light';
  }

  angularGridReady1(angularGrid: AngularGridInstance) {
    this.angularGrid1 = angularGrid;
  }

  isBrowserDarkModeEnabled() {
    return window.matchMedia?.('(prefers-color-scheme: dark)').matches ?? false;
  }

  prepareGrid() {
    this.columnDefinitions1 = [
      { id: 'title', name: 'Title', field: 'title', sortable: true },
      {
        id: 'duration',
        name: 'Duration (days)',
        field: 'duration',
        sortable: true,
      },
      { id: '%', name: '% Complete', field: 'percentComplete', sortable: true },
      {
        id: 'start',
        name: 'Start',
        field: 'start',
        formatter: Formatters.dateIso,
      },
      {
        id: 'finish',
        name: 'Finish',
        field: 'finish',
        formatter: Formatters.dateIso,
      },
      {
        id: 'effort-driven',
        name: 'Effort Driven',
        field: 'effortDriven',
        sortable: true,
      },
    ];
    this._darkModeGrid1 = this.isBrowserDarkModeEnabled();
    this.gridOptions1 = {
      darkMode: this._darkModeGrid1,
      enableAutoResize: false,
      enableSorting: true,
      gridHeight: 225,
      gridWidth: 800,
    };

    // copy the same Grid Options and Column Definitions to 2nd grid
    // but also add Pagination in this grid
    this.columnDefinitions2 = this.columnDefinitions1;
    this.gridOptions2 = {
      ...this.gridOptions1,
      ...{
        darkMode: false,
        enablePagination: true,
        pagination: {
          pageSizes: [5, 10, 20, 25, 50],
          pageSize: 5,
        },
      },
    };

    // mock some data (different in each dataset)
    this.dataset1 = this.mockData(NB_ITEMS);
    this.dataset2 = this.mockData(NB_ITEMS);
  }

  mockData(count: number) {
    // mock a dataset
    const mockDataset = [];
    for (let i = 0; i < count; i++) {
      const randomYear = 2000 + Math.floor(Math.random() * 10);
      const randomMonth = Math.floor(Math.random() * 11);
      const randomDay = Math.floor(Math.random() * 29);
      const randomPercent = Math.round(Math.random() * 100);

      mockDataset[i] = {
        id: i,
        title: 'Task ' + i,
        duration: Math.round(Math.random() * 100) + '',
        percentComplete: randomPercent,
        start: new Date(randomYear, randomMonth + 1, randomDay),
        finish: new Date(randomYear + 1, randomMonth + 1, randomDay),
        effortDriven: i % 5 === 0,
      };
    }

    return mockDataset;
  }

  toggleDarkModeGrid1() {
    this._darkModeGrid1 = !this._darkModeGrid1;
    if (this._darkModeGrid1) {
      document.querySelector('.grid-container1')?.classList.add('dark-mode');
    } else {
      document.querySelector('.grid-container1')?.classList.remove('dark-mode');
    }
    this.angularGrid1.slickGrid?.setOptions({ darkMode: this._darkModeGrid1 });
  }
}


### HTML:

<angular-slickgrid
  gridId="grid2"
  [columnDefinitions]="columnDefinitions2"
  [gridOptions]="gridOptions2"
  [dataset]="dataset2"
>
</angular-slickgrid>

Stackblitz Demo -> cd test -> npm i -> npm run start


Modular approach

Follow similar steps upto standalone step, then jump to here, open the app.module.ts

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

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AngularSlickgridModule } from 'angular-slickgrid';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    AngularSlickgridModule.forRoot()
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Stackblitz Demo

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for providing this detailed answer, I'm the author of Angular-Slickgrid and never had a chance to try the Standalone version yet, so this is really helpful :)
@ghiscoding omg, thank you for this awesome frontend package, no problem!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.