首页 > 解决方案 > Trying to filter through a list: "TypeError: Cannot read property 'Name' of null"

问题描述

I'm trying to filter through a list, but keep getting "TypeError: Cannot read property 'Name' of null". I can't seem to figure out why locations.Name would be null. I purposely use this.locations = initializeLocations() to prevent it. The data is there and my list gets generated well (with ngFor).

Typescript

//Imports

@Component({
  selector: 'app-locaties',
  templateUrl: './locaties.component.html',
  styleUrls: ['./locaties.component.css'],
})
export class LocatiesComponent implements OnInit {
  // the full list
  masterLocations: any = [];
  locations: any = [];
  user;

  constructor(
    private toolbarTitle: ToolbarTitleService,
    public popoverController: PopoverController,
    private syncService: SyncServiceService,
    private userService: UserService
  ) {}

  async ngOnInit() {
    this.toolbarTitle.setToolbarTitle('Locaties');
    this.user = await this.userService.getUser();
    // Haalt alle shops van de gebruiker op en zet ze in locations
    await this.initializeLocations();
  }

  async initializeLocations() {
    this.masterLocations = await this.syncService.getShops(this.user);

    if (this.locations.length === 0) {
      this.locations = JSON.parse(JSON.stringify(this.masterLocations));
    }
  }

  // Popover
  async presentPopover(ev: any, Contact: any) {
    const popover = await this.popoverController.create({
      component: PopoverComponent,
      componentProps: {
        phones: Contact.Phones[0].Number,
        email: Contact.Email,
        street: Contact.Addresses[0].Street1,
        city: Contact.Addresses[0].City,
      },
      event: ev,
      translucent: true,
    });
    return await popover.present();
  }

  filterList(ev: any) {
    const val = ev.target.value;

    if (val && val.trim() != '') {
      const clone = JSON.parse(JSON.stringify(this.masterLocations));

      this.locations = clone.filter((item) => {
        return item.Name.toLowerCase().indexOf(val.toLowerCase()) > -1;
      });
    } else {
      this.locations = this.masterLocations;
    }
  }

  selectVal(val) {
    alert('you have selected = ' + val);
  }
}

HTML

<ion-content fullscreen>
  <!-- Searchbar with a placeholder -->

  <!-- (ionChange)="ionChange($event)" -->
  <ion-searchbar
    debounce="1000"
    (ionInput)="filterList($event)"
    placeholder="Zoek een locatie"
  ></ion-searchbar>

  <ion-grid>
    <ion-row>
      <!-- locatie cards -->
      <ion-col class="row1" size="11">
        <ion-list lines="none">
          <ion-item
            (click)="selectVal(location.Name)"
            *ngFor="let location of locations"
          >
            <ion-card class="locatieCard">
              <ion-item>
                <img
                  class="locatieImg"
                  src="assets/spar_img.jpg"
                  slot="start"
                />
                <ion-grid>
                  <ion-row>
                    <ion-card-subtitle>{{ location.Name }}</ion-card-subtitle>
                  </ion-row>
                  <ion-row>
                    <ion-button
                      size="small"
                      fill="clear"
                      (click)="presentPopover($event, location.Contact)"
                    >
                      Meer info
                    </ion-button>
                  </ion-row>
                </ion-grid>
              </ion-item>
            </ion-card>
          </ion-item>
        </ion-list>
      </ion-col>

      <ion-col class="row2" size="1"> ion col 2 </ion-col>
    </ion-row>
  </ion-grid>
</ion-content>

This is what getShops() in initializeLocations() returns: getSgops return

this is the code:

  getShops(user: any) {
    const selector = {
      _id: { $in: user.Shops },
    };
    return this.dbService.localDB
      .find({
        selector,
      })
      .then((result: any) => {
        console.log('SHOPS: ', result.docs);
        return result.docs;
      });
  }

Error message enter image description here

标签: angulartypescriptionic-frameworkfrontendfiltering

解决方案


好吧,我的假设是,您将异步与同步混合在一起。您在filterList()方法中做的第一件事是调用this.initializeLocations();. 哪个触发

this.locations = await this.syncService.getShops(this.user);

尽管您在await这里使用,但从filterList(). 它不会等待此操作完成。

因此,在处理此呼叫时,this.locations您会在尝试过滤它时再次使用它。而且我认为上面的异步过程已经清除了数组并等待新值将其放入。

消除

this.initializeLocations();

从你的过滤方法。这会成功的。

现在您必须注意将列表用作数据库而不是被覆盖。所以我们现在要做的是,用masterLocations.

export class LocatiesComponent implements OnInit {
    // the full list
    masterLocations: any = [];

    // the filtered list
    locations: any = [];

    // the user
    user;

在此处获取主列表

async initializeLocations() {
    this.masterLocations = await this.syncService.getShops(this.user);
}

和这里的过滤列表。随着JSON.pare(JSON.stringify())我们生成整个列表的克隆。

filterList(ev: any) {
    const val = ev.target.value;

    if (val && val.trim() != '') {
        const clone = JSON.parse(JSON.stringify(this.masterLocations));
 
        this.locations = clone.filter((item) => {
           return item.Name.toLowerCase().indexOf(val.toLowerCase()) > -1;
        });
    } 
     else {
          this.locations = JSON.parse(JSON.stringify(this.masterLocations));
    }

}

推荐阅读