Почему я получаю эту ошибку в своем приложении Angular? Неперехваченный (в обещании): NullInjectorError

#angular #primeng

#angular #primeng

Вопрос:

Я не очень разбираюсь в Angular и PrimeNG, и я нахожу следующую проблему, пытаясь воспроизвести этот пример демонстрации таблицы PrimeNG (код предоставлен на вкладке «Исходный код» этой страницы):https://www.primefaces.org/primeng/showcase/#/table

В основном я пытаюсь поместить этот код в компонент моего приложения (затем я адаптирую его к своим вариантам использования).

Итак, у меня есть этот класс компонента:

 import { Component, OnInit, ViewChild } from '@angular/core';
import { Customer, Representative } from './customer';
import { Table } from 'primeng';
import { CustomerService } from './customerservice';

@Component({
  selector: 'app-gestione-ordini',
  templateUrl: './gestione-ordini.component.html',
  styleUrls: ['./gestione-ordini.component.css']
})
export class GestioneOrdiniComponent implements OnInit {

  customers: Customer[];

  selectedCustomers: Customer[];

  representatives: Representative[];

  statuses: any[];

  loading: boolean = true;

  @ViewChild('dt') table: Table;

  constructor(private customerService: CustomerService) { }

  ngOnInit() {
    this.customerService.getCustomersLarge().then(customers => {
        this.customers = customers;
        this.loading = false;
    });

    this.representatives = [
        {name: "Amy Elsner", image: 'amyelsner.png'},
        {name: "Anna Fali", image: 'annafali.png'},
        {name: "Asiya Javayant", image: 'asiyajavayant.png'},
        {name: "Bernardo Dominic", image: 'bernardodominic.png'},
        {name: "Elwin Sharvill", image: 'elwinsharvill.png'},
        {name: "Ioni Bowcher", image: 'ionibowcher.png'},
        {name: "Ivan Magalhaes",image: 'ivanmagalhaes.png'},
        {name: "Onyama Limba", image: 'onyamalimba.png'},
        {name: "Stephen Shaw", image: 'stephenshaw.png'},
        {name: "XuXue Feng", image: 'xuxuefeng.png'}
    ];

    this.statuses = [
        {label: 'Unqualified', value: 'unqualified'},
        {label: 'Qualified', value: 'qualified'},
        {label: 'New', value: 'new'},
        {label: 'Negotiation', value: 'negotiation'},
        {label: 'Renewal', value: 'renewal'},
        {label: 'Proposal', value: 'proposal'}
    ]
  }

  onActivityChange(event) {
    const value = event.target.value;
    if (value amp;amp; value.trim().length) {
        const activity = parseInt(value);

        if (!isNaN(activity)) {
            this.table.filter(activity, 'activity', 'gte');
        }
    }
  }

  onDateSelect(value) {
      this.table.filter(this.formatDate(value), 'date', 'equals')
  }

  formatDate(date) {
      let month = date.getMonth()   1;
      let day = date.getDate();

      if (month < 10) {
          month = '0'   month;
      }

      if (day > 10) {
          day = '0'   day;
      }

      return date.getFullYear()   '-'   month   '-'   day;
  }

  onRepresentativeChange(event) {
      this.table.filter(event.value, 'representative', 'in')
  }


}
  

Тогда это служба CustomerService, используемая в предыдущем классе компонента:

 import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Customer } from './customer';


@Injectable()
export class CustomerService {

    constructor(private http: HttpClient) { }

    getCustomersSmall() {
        return this.http.get<any>('assets/showcase/data/customers-small.json')
            .toPromise()
            .then(res => <Customer[]>res.data)
            .then(data => { return data; });
    }

    getCustomersMedium() {
        return this.http.get<any>('assets/showcase/data/customers-medium.json')
            .toPromise()
            .then(res => <Customer[]>res.data)
            .then(data => { return data; });
    }

    getCustomersLarge() {
        return this.http.get<any>('assets/showcase/data/customers-large.json')
            .toPromise()
            .then(res => <Customer[]>res.data)
            .then(data => { return data; });
    }

    getCustomersXLarge() {
        return this.http.get<any>('assets/showcase/data/customers-xlarge.json')
            .toPromise()
            .then(res => <Customer[]>res.data)
            .then(data => { return data; });
    }

}
  

И это связанная страница просмотра html для этого компонента:

 <div class="card">
  <p-table #dt [value]="customers" [(selection)]="selectedCustomers" dataKey="id" styleClass="p-datatable-customers" [rowHover]="true"
      [rows]="10" [showCurrentPageReport]="true" [rowsPerPageOptions]="[10,25,50]" [loading]="loading"
      [paginator]="true" currentPageReportTemplate="Showing {first} to {last} of {totalRecords} entries"
      [filterDelay]="0" [globalFilterFields]="['name','country.name','representative.name','status']">
      <ng-template pTemplate="caption">
          <div class="table-header">
              List of Cars
              <span class="p-input-icon-left">
                  <i class="pi pi-search"></i>
                  <input pInputText type="text" (input)="dt.filterGlobal($event.target.value, 'contains')" placeholder="Global Search" />
              </span>
          </div>
      </ng-template>
      <ng-template pTemplate="header">
          <tr>
              <th style="width: 3rem"></th>
              <th pSortableColumn="name">Name <p-sortIcon field="name"></p-sortIcon></th>
              <th pSortableColumn="country.name">Country <p-sortIcon field="country.name"></p-sortIcon></th>
              <th pSortableColumn="representative.name">Representative <p-sortIcon field="representative.name"></p-sortIcon></th>
              <th pSortableColumn="date">Date <p-sortIcon field="date"></p-sortIcon></th>
              <th pSortableColumn="status">Status <p-sortIcon field="status"></p-sortIcon></th>
              <th pSortableColumn="activity">Activity <p-sortIcon field="activity"></p-sortIcon></th>
              <th style="width: 8rem"></th>
          </tr>
          <tr>
              <th>
                  <p-tableHeaderCheckbox></p-tableHeaderCheckbox>
              </th>
              <th>
                  <input pInputText type="text" (input)="dt.filter($event.target.value, 'name', 'startsWith')" placeholder="Search by Name" class="p-column-filter">
              </th>
              <th>
                  <input pInputText type="text" (input)="dt.filter($event.target.value, 'country.name', 'contains')" placeholder="Search by Country" class="p-column-filter">
              </th>
              <th>
                  <p-multiSelect [options]="representatives" placeholder="All" (onChange)="onRepresentativeChange($event)" styleClass="p-column-filter" optionLabel="name">
                      <ng-template let-option pTemplate="item">
                          <div class="p-multiselect-representative-option">
                              <img [alt]="option.label" src="assets/showcase/images/demo/avatar/{{option.value.image}}" width="32" style="vertical-align: middle" />
                              <span class="p-ml-1">{{option.label}}</span>
                          </div>
                      </ng-template>
                  </p-multiSelect>
              </th>
              <th>
                  <p-calendar (onSelect)="onDateSelect($event)" (onClearClick)="dt.filter('', 'date', 'equals')" [showButtonBar]="true" styleClass="p-column-filter" placeholder="Registration Date" [readonlyInput]="true" dateFormat="yy-mm-dd"></p-calendar>
              </th>
              <th>
                  <p-dropdown [options]="statuses" (onChange)="dt.filter($event.value, 'status', 'equals')" styleClass="p-column-filter" placeholder="Select a Status" [showClear]="true">
                      <ng-template let-option pTemplate="item">
                          <span [class]="'customer-badge status-'   option.value">{{option.label}}</span>
                      </ng-template>
                  </p-dropdown>
              </th>
              <th>
                  <input pInputText type="text" (input)="onActivityChange($event)" placeholder="Minimum" class="p-column-filter" >
              </th>
              <th></th>
          </tr>
      </ng-template>
      <ng-template pTemplate="body" let-customer>
          <tr class="p-selectable-row">
              <td>
                  <p-tableCheckbox [value]="customer"></p-tableCheckbox>
              </td>
              <td>
                  <span class="p-column-title">Name</span>
                  {{customer.name}}
              </td>
              <td>
                  <span class="p-column-title">Country</span>
                  <img src="assets/showcase/images/demo/flag/flag_placeholder.png" [class]="'flag flag-'   customer.country.code" width="30">
                  <span class="image-text">{{customer.country.name}}</span>
              </td>
              <td>
                  <span class="p-column-title">Representative</span>
                  <img [alt]="customer.representative.name" src="assets/showcase/images/demo/avatar/{{customer.representative.image}}" width="32" style="vertical-align: middle" />
                  <span class="image-text">{{customer.representative.name}}</span>
              </td>
              <td>
                  <span class="p-column-title">Date</span>
                  {{customer.date}}
              </td>
              <td>
                  <span class="p-column-title">Status</span>
                  <span [class]="'customer-badge status-'   customer.status">{{customer.status}}</span>
              </td>
              <td>
                  <span class="p-column-title">Activity</span>
                  <p-progressBar [value]="customer.activity" [showValue]="false"></p-progressBar>
              </td>
              <td style="text-align: center">
                  <button pButton type="button" class="p-button-secondary" icon="pi pi-cog"></button>
              </td>
          </tr>
      </ng-template>
      <ng-template pTemplate="emptymessage">
          <tr>
              <td colspan="8">No customers found.</td>
          </tr>
      </ng-template>
  </p-table>
</div>
  

Он компилируется правильно, но проблема в том, что когда я запускаю свое приложение, вместо получения ожидаемой таблицы я получаю это сообщение об ошибке:

 core.js:6228 ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[CustomerService -> CustomerService -> CustomerService]: 
  NullInjectorError: No provider for CustomerService!
NullInjectorError: R3InjectorError(AppModule)[CustomerService -> CustomerService -> CustomerService]: 
  NullInjectorError: No provider for CustomerService!
    at NullInjector.get (core.js:1085)
    at R3Injector.get (core.js:16955)
    at R3Injector.get (core.js:16955)
    at R3Injector.get (core.js:16955)
    at NgModuleRef$1.get (core.js:36329)
    at Object.get (core.js:33972)
    at getOrCreateInjectable (core.js:5848)
    at Module.ɵɵdirectiveInject (core.js:21103)
    at NodeInjectorFactory.GestioneOrdiniComponent_Factory [as factory] (gestione-ordini.component.ts:11)
    at getNodeInjectable (core.js:5993)
    at resolvePromise (zone-evergreen.js:798)
    at resolvePromise (zone-evergreen.js:750)
    at zone-evergreen.js:860
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:41632)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)
    at Zone.runTask (zone-evergreen.js:167)
    at drainMicroTaskQueue (zone-evergreen.js:569)
  

Почему я получаю эту ошибку? В чем может быть проблема?

Ответ №1:

Попробуйте добавить

 @Injectable({provided in: "root"})
  

К вашему классу обслуживания. Это включит его в корневой инжектор и сделает доступным для любого объекта в вашем приложении.

В качестве альтернативы, если вы хотите, чтобы эта служба была доступна только для части вашего приложения, вам нужно включить ее в NgModule в массив provides