Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/32.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular MD Paginator错误:data.slice不是MapSubscriber上的函数_Angular_Angular Material2 - Fatal编程技术网

Angular MD Paginator错误:data.slice不是MapSubscriber上的函数

Angular MD Paginator错误:data.slice不是MapSubscriber上的函数,angular,angular-material2,Angular,Angular Material2,Web上没有关于此错误的任何信息:-( 它发生在MD数据表的my MD Paginator中的两个操作中 1) 当我点击下一页的箭头时 2) 当我尝试更改页面大小时,比如从5行更改为10行 应用程序因此错误而崩溃。除此之外,数据表显示一切正常。它显示数据库中的前5个项目,在分页部分底部的项目计数为8,即数据库中的总数 知道发生了什么事吗?还有解决办法吗?我试图在服务中放入尽可能多的代码,因为其他组件将使用它 首先是html。请注意,我在最后两列的行中添加了按钮,并在最后一列中隐藏了行的内容。按钮

Web上没有关于此错误的任何信息:-(

它发生在MD数据表的my MD Paginator中的两个操作中

1) 当我点击下一页的箭头时

2) 当我尝试更改页面大小时,比如从5行更改为10行

应用程序因此错误而崩溃。除此之外,数据表显示一切正常。它显示数据库中的前5个项目,在分页部分底部的项目计数为8,即数据库中的总数

知道发生了什么事吗?还有解决办法吗?我试图在服务中放入尽可能多的代码,因为其他组件将使用它

首先是html。请注意,我在最后两列的行中添加了按钮,并在最后一列中隐藏了行的内容。按钮和隐藏行工作正常。我希望它们不是问题,因为我需要它们。我在html和component.ts中的相关displayedColumns中将它们注释掉,没有帮助

<md-table #table [dataSource]="dataSource">

      <!-- First Name Column -->
      <ng-container cdkColumnDef="firstName">
        <md-header-cell *cdkHeaderCellDef> Name </md-header-cell>
        <md-cell *cdkCellDef="let row"> {{row.firstName}} </md-cell>
      </ng-container>

      <!-- Las Name Column -->
      <ng-container cdkColumnDef="lastName">
        <md-header-cell *cdkHeaderCellDef> Last Name </md-header-cell>
        <md-cell *cdkCellDef="let row">  {{row.lastName}} </md-cell>
      </ng-container>

      <!-- Title Column -->
      <ng-container cdkColumnDef="mainSkillTitle">
        <md-header-cell *cdkHeaderCellDef> Title </md-header-cell>
        <md-cell *cdkCellDef="let row"> {{row.mainSkillTitle}} </md-cell>
      </ng-container>

      <!-- Main Skills Column -->
      <ng-container cdkColumnDef="mainSkills">
        <md-header-cell *cdkHeaderCellDef> Main Skills </md-header-cell>
        <md-cell *cdkCellDef="let row"> {{row.mainSkills}} </md-cell>
      </ng-container>

      <!-- Delete Buttons Column -->
      <ng-container cdkColumnDef="delete">
        <md-header-cell *cdkHeaderCellDef> Delete </md-header-cell>
        <md-cell *cdkCellDef="let row">
          <button (click)="deleteMember(row.$key)">Delete</button> </md-cell>
      </ng-container>

      <!-- Edit button Column -->
      <ng-container cdkColumnDef="edit">
        <md-header-cell *cdkHeaderCellDef> Edit </md-header-cell>
        <md-cell *cdkCellDef="let row">
          <button (click)="goToDetailPage(row.$key)">Edit</button> </md-cell>
      </ng-container>

      <!-- Database key Column -->

      <ng-container cdkColumnDef="key">
        <md-header-cell *cdkHeaderCellDef class="hiddenField"> Key </md-header-cell>
        <md-cell *cdkCellDef="let row" class="hiddenField"> {{row.$key}} </md-cell>
      </ng-container>


      <md-header-row *cdkHeaderRowDef="displayedColumns"></md-header-row>
      <md-row *cdkRowDef="let row; columns: displayedColumns;"></md-row>


    </md-table>
    <md-paginator #paginator
                  [length]="dataLength?.length"
                  [pageIndex]="0"
                  [pageSize]="5"
                  [pageSizeOptions]="[5, 10, 25, 100]">
    </md-paginator>

简单地说,
data
似乎不是一个数组(或者是一个带有
slice
方法的对象),在这个数组中,您调用的是
data.slice()
,它位于传递给
.map()
的方法内部

违规线路:

constdataslice=data.slice();
一个解决方案:

const dataSlice = Array.isArray(data) ? data.slice() : [];

如果
数据
不是数组,它实际上取决于您要执行的操作。

可观察。merge
不会同时返回
数据
页面
。相反,它只返回最后发出的值。当数据库发送事件时,将结果存储到
数据中
,并对其进行正确切片。当分页器发送事件时,您将页面事件存储到
数据中
,并错误地对其进行切片

要解决这个问题,您有几个选项。首先,您可以使用另一个合并功能,如
combinelatetest
,它将提供您列出的值
(数据,页面)
。问题是,它将等待所有流至少发出一次,但分页器在与交互之前不会发出。您可以通过让
this.paginator.page.startsWith(null)
以发出的值开始添加起始值

第二,你可以有一个单独的订阅来存储你的数据

  this.memberDatabase.getMembers().subscribe(data => this.data = data)

然后进行合并,但不要捕获任何值,只需对数据使用
this.data
,对当前页面值使用
this.paginator

经过几天的实验和研究,我找到了答案。这是如何使用MD Paginator设置MD表,并从外部源(如Firebase)导入数据。我为源代码和数据库类使用了一个服务,大部分代码都进入了该服务。我出现错误的原因是因为我没有弄清楚如何连接MemberDatabase类的前两行。这需要创建数据库类并重构源类。Ben和Andrew的解决方案都不起作用,我尝试了许多排列。然而,安德鲁解决方案的第一段给了我自己解决这个问题所需要的洞察力。非常感谢安德鲁

member-admin.service.ts

import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { FirebaseApp } from 'angularfire2';
import { Inject, Injectable } from '@angular/core';

import { MemberModel } from './member-admin.model';
import { SuccessService } from '../../../shared/success.service';

// Data Table imports.
import { MdPaginator } from '@angular/material';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/combineLatest';
import 'rxjs/add/operator/map';


@Injectable()
export class MembersAdminService {

  private membersData$: FirebaseListObservable<MemberModel[]>;

  constructor(
    public af: AngularFireDatabase,
    private successService: SuccessService,

    // For Create and Update functions.
    @Inject(FirebaseApp) fb) {
      this.membersData$ = af.list('Members');
    }

// ... CRUD stuff not relevant to the MD Table ...


// *** MD DATA TABLE SERVICES. ***


@Injectable()
export class MemberDatabase {

    /* Stream that emits whenever the data has been modified. */
    public dataChange: BehaviorSubject<MemberModel[]> = new BehaviorSubject<MemberModel[]>([]);
    get data(): MemberModel[] {
        return this.dataChange.value; }

    // Connection to remote db.
    private database = this.memberAdminService.af.list('Members', {
        query: {
            orderByChild: 'lastName'
        }
    });
    public getMembers(): FirebaseListObservable<MemberModel[]> {
        return this.database;
    }


    constructor(private memberAdminService: MembersAdminService) {
        this.getMembers()
            .subscribe(data => this.dataChange.next(data));
    }
}


@Injectable()
export class MembersAdminSource extends DataSource<MemberModel> {


    constructor(
        private memberDatabase: MemberDatabase,
        private paginator: MdPaginator) {
        super();
    }


    /** Connect function called by the table to retrieve one stream containing the data to render. */
    connect(): Observable<MemberModel[]> {

      const displayDataChanges = [
          this.memberDatabase.dataChange,
          this.paginator.page,
      ];

      return Observable
          .merge(...displayDataChanges) // Convert object to array with spread syntax.
          .map(() => {
              const dataSlice = this.memberDatabase.data.slice(); // Data removed from viewed page.

              // Get the page's slice per pageSize setting.
              const startIndex = this.paginator.pageIndex * this.paginator.pageSize;

              const dataLength = this.paginator.length;  // This is for the counter on the DOM.

              return dataSlice.splice(startIndex, this.paginator.pageSize);
          });
    }
    disconnect() {}
}

模板中没有任何更改

我不太明白。这是console.log:dataSlice(8)[Object,Object,Object,Object,Object,Object,Object]每个对象都有数据,但我刚刚注意到其中只有3个对象,而不是它所说的8个对象。页面有5行,所以这里只有提醒,内容是数据库中的最后三行。我会试试你的建议。其中一次通过
数据
的不是数组。由于控制台在您的切片之后进行日志记录,因此您将丢失它。在切片之前添加一个
console.log(data)
,查看您事先得到了什么。此代码来自AM Paginator文档:。但是我已经修改了它,以便使用服务.Console.log(数据):(8)[Object,Object,Object,Object,Object,Object,Object]所有对象都有正确的数据并且都在那里。看起来像一个数组,但我是一个noob。Ben,我用你的代码替换了我的代码,但是当我点击下一页按钮时,数据片是空的。dataSlice[]长度:0。谢谢Andrew,我需要一些时间来解决这个问题。同时研究Rx。。。我复制并粘贴了AM2 Paginator文档中的代码,并试图理解它。他们将所有代码放在一个component.ts中,这不是我们任何人的编码方式,因此我正在努力将其分离,因为它本应呈现。顺便说一下,console.log正在显示第0页。我认为第一页是正确的,但第二页正在使应用程序崩溃。安德鲁,你说的话(对我)开始有意义了。单击下一页按钮后,但在应用程序崩溃之前,我在控制台中获得以下数据:Object{pageIndex:1,pageSize:5,length:8}length:8 pageIndex:1 pageSize:5第一次调用数据包含数据库中的所有8个对象。第2页包含上述内容。控制台显示的第1页对于数组来说是正确的,实际上是第2页,但它从第0页开始。我正在研究你的选择。我尝试了我能想到的两种解决方案的每一种排列方式,但都不起作用。不过我觉得你走的是对的。我将.merge替换为CombineTest,它无法加载包含任何内容的表,但无法为有效的startsWith语句找到位置。将其放入“const displayDataChanges=[…'创建了一个有趣的无限循环:-)对于第二个解决方案,我将'this.data…'放在.map中,并尝试了订阅的多个位置,但出现了很多错误。我不认为删除代码是解决方案的一部分。在AM2文档中,这是在export ExampleDatabase中。我已经有一个Firebase db,所以我没有将其包含在代码中,但我认为没有这两条语句很重要。它们可能属于服务。dataChange:BehaviorSubject=new BehaviorSubject([]);get data():
  this.memberDatabase.getMembers().subscribe(data => this.data = data)
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database';
import { FirebaseApp } from 'angularfire2';
import { Inject, Injectable } from '@angular/core';

import { MemberModel } from './member-admin.model';
import { SuccessService } from '../../../shared/success.service';

// Data Table imports.
import { MdPaginator } from '@angular/material';
import { DataSource } from '@angular/cdk';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/combineLatest';
import 'rxjs/add/operator/map';


@Injectable()
export class MembersAdminService {

  private membersData$: FirebaseListObservable<MemberModel[]>;

  constructor(
    public af: AngularFireDatabase,
    private successService: SuccessService,

    // For Create and Update functions.
    @Inject(FirebaseApp) fb) {
      this.membersData$ = af.list('Members');
    }

// ... CRUD stuff not relevant to the MD Table ...


// *** MD DATA TABLE SERVICES. ***


@Injectable()
export class MemberDatabase {

    /* Stream that emits whenever the data has been modified. */
    public dataChange: BehaviorSubject<MemberModel[]> = new BehaviorSubject<MemberModel[]>([]);
    get data(): MemberModel[] {
        return this.dataChange.value; }

    // Connection to remote db.
    private database = this.memberAdminService.af.list('Members', {
        query: {
            orderByChild: 'lastName'
        }
    });
    public getMembers(): FirebaseListObservable<MemberModel[]> {
        return this.database;
    }


    constructor(private memberAdminService: MembersAdminService) {
        this.getMembers()
            .subscribe(data => this.dataChange.next(data));
    }
}


@Injectable()
export class MembersAdminSource extends DataSource<MemberModel> {


    constructor(
        private memberDatabase: MemberDatabase,
        private paginator: MdPaginator) {
        super();
    }


    /** Connect function called by the table to retrieve one stream containing the data to render. */
    connect(): Observable<MemberModel[]> {

      const displayDataChanges = [
          this.memberDatabase.dataChange,
          this.paginator.page,
      ];

      return Observable
          .merge(...displayDataChanges) // Convert object to array with spread syntax.
          .map(() => {
              const dataSlice = this.memberDatabase.data.slice(); // Data removed from viewed page.

              // Get the page's slice per pageSize setting.
              const startIndex = this.paginator.pageIndex * this.paginator.pageSize;

              const dataLength = this.paginator.length;  // This is for the counter on the DOM.

              return dataSlice.splice(startIndex, this.paginator.pageSize);
          });
    }
    disconnect() {}
}
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs/Subject';

// For MD Data Table.
import { MdPaginator } from '@angular/material';
import { MembersAdminService, MembersAdminSource, MemberDatabase } from './member-admin.service';

import { ConfirmService } from '../../../shared/confirm.service';
import { MemberModel } from './member-admin.model';


@Component({
  selector: 'app-all-members',
  templateUrl: './all-members.component.html'
})


export class AllMembersComponent implements OnInit {

  membersData: MemberModel[];
  private result: boolean;
  allMembers: MemberModel[];

  // For search
  startAt = new Subject();
  endAt = new Subject();
  lastKeypress: 0;

    // For MD data table.

  // private memberDatabase = new MemberDatabase();  // Requires a param but? Moved to constructor.
  private dataSource: MembersAdminSource | null;
  private displayedColumns = [
      'firstName',
      'lastName',
      'mainSkillTitle',
      'mainSkills',
      'delete',
      'key'
  ];

  @ViewChild(MdPaginator)
  paginator: MdPaginator;

  public dataLength: any; // For member counter on DOM.

  constructor(
      private membersAdminService: MembersAdminService,
      private memberDatabase: MemberDatabase,
      private router: Router,
      private confirmService: ConfirmService
  ) {}

  ngOnInit() {

      this.memberDatabase.getMembers()
          .subscribe(members => {
              this.dataSource = new MembersAdminSource(this.memberDatabase, this.paginator);
              this.dataLength = members;
          });
    }