Ionic / Firebase - 错误拼接不是函数(reorderArray)

时间:2017-11-20 20:36:10

标签: ionic-framework

我已经打了几天...尝试使用(ionItemReorder)=" reorderItems($ event)"重新排序列表。我有一张我从FireBase获得的歌曲列表。当我触发reOrderItems click事件时,我收到一个错误:TypeError:array.splice不是reorderArray的函数

我认为这可能是我定义"歌曲"的方式非常简单。我尝试了几种不同的方式......但此时我只是抓住了稻草。

任何建议都将不胜感激。谢谢! ER

打字稿

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, reorderArray } from 'ionic-angular';
import { AngularFireModule} from 'angularfire2';
import { AngularFireDatabase } from 'angularfire2/database';

@IonicPage()
@Component({
  selector: 'page-songs',
  templateUrl: 'songs.html',
})
export class SongsPage {

  //songs: any = {};
  //songs = {};
  //songs = [];
  //songs: any = [];
  songs: any;  
  btnName: any = 'Reorder';
  flag: any = false;

  constructor(
    public navCtrl: NavController, 
    public navParams: NavParams,
    public afd: AngularFireDatabase
  ) 
  {    
    this.songs = this.afd.list('/songs/').valueChanges();    
  }

  //Button in navbar to toggle reordering the list of songs
  actionBtn(){
    if (this.btnName == 'Reorder') {
      this.btnName = 'Done';
      this.flag = true;
    }
    else{
      this.btnName = 'Reorder';
      this.flag = false;
    }
  };

  reorderItems(indexes){
    //let element = this.songs[indexes.from];
    //this.songs.splice(indexes.from, 1);
    //this.songs.splice(indexes.to, 0, element);
    this.songs = reorderArray(this.songs, indexes);    
   };

  showChords(song){
    this.navCtrl.push('ChordsPage', song)
  }

}

HTML

<ion-header>
  <ion-navbar>
    <ion-title>Songlist</ion-title>
    <ion-buttons end>
      <button ion-button small clear (click)="actionBtn();">
        {{btnName}}
      </button>
    </ion-buttons>
  </ion-navbar>
</ion-header>

<ion-content>
    <ion-list reorder="{{flag}}" (ionItemReorder)="reorderItems($event)">
        <ion-item-sliding *ngFor="let song of songs | async ; let i = index">

          <ion-item>
              <h2>{{i+1}}. {{ song.Title}}</h2>
              <p>{{song.Artist}}</p>        
          </ion-item>                

          <ion-item-options side="right">
              <button ion-button (click)="showChords(song)">Chords</button>
            </ion-item-options>

            <ion-item-options side="left">
                <button ion-button color="danger" (click)="removeSong(song)">Delete
                  <ion-icon name="trash"></ion-icon>
                </button>
            </ion-item-options>

              </ion-item-sliding>
      </ion-list>
</ion-content>

3 个答案:

答案 0 :(得分:0)

订阅Observablemap items以推送到songs数组。此外,在初始化时使用生命周期挂钩ionViewDidLoad而不是constructor来执行操作。

import { AngularFireDatabase } from 'angularfire2/database';
import { ISubscription } from 'rxjs/Subscription';
import { OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';

...

export class ... implements OnDestroy {

    songslist: Observable<any[]>;
    subscription: ISubscription;
    songs: any[];

    constructor(...

    ionViewDidLoad() {

        this.songslist = this.afd.list<Item>('songs').valueChanges();
        this.subscription = songslist.subscribe(items => {
            return items.map(item => { this.songs.push(item); });
        });

    }

    ...

    reorderItems(...

    ...

    ngOnDestroy {
        this.subscription.unsubscribe(); // Make sure to unsubscribe, don't leave them open.
    }
} 

答案 1 :(得分:0)

尝试完成非常相似的事情 - 除了使用Firestore而不是实时数据库 - 我想让我的头靠在墙上,但最后让它工作,所以希望它对你或其他人有帮助,即使有些事情会略有不同。

当你试图对一个不是数组的东西执行函数时,array.splice不是函数错误,在这种情况下,由于我理解的原因,observable似乎被返回为单个对象。

为了让事情有效,我分别声明了这些变量:

photoCollectionRef:AngularFirestoreCollection < PhotoSlide>; 
photo$: Observable < PhotoSlide [] >; 
photo = {} as PhotoSlide; 
photoArray: any=[];

然后将每个值设置如下

this.photoCollectionRef = this.afs.collection('posts').doc(this.postId).collection('photos/', ref => ref.orderBy('index'));
this.photo$ = this.photoCollectionRef.valueChanges();

this.photo$.take(1).subscribe((pictures) => {
  pictures.forEach(p=>{
   return  this.photoArray.push({index:p.index, photoURL: p.photoURL, id:p.id })
  })
});

在模板文件中* ngFor在photoArray的照片上循环(没有异步管道),从项目组调用的reorderItem函数与离子文档中的标准单行语法完美配合。

然后,要更新Firestore Collection中的索引,我会在修改列表顺序后从一个可见的按钮调用以下函数:

saveNewOrder(){
this.photoArray.forEach((element, i) => {
  this.photoCollectionRef.doc(element.id).update({
    index: i
  });
});

}

我应该注意,在添加新文档而不仅仅是.add时,我总是使用.createId()方法然后使用.doc(newId).set({id:newId etc})因为我发现它少了很多比使用.snapshotChanges和map函数而不仅仅是.valueChanges()更难以做到这一点 - 这就是为什么上面的函数与显示的语法一起工作

此外,如果您在订阅之前没有使用rxjs take(1)运算符,那么一开始看起来一切正常,但在执行saveNewOrder函数后,列表会重复多次

答案 2 :(得分:0)

我很晚才回到这里,但这是我试图解释我是如何工作的 **警告 - 我是一个业余爱好者编码器,所以如果我使用错误的术语解释或者如果我只是理解它错了那么我会提前道歉......代码可以工作:)。

目标是使用Firebase的新版本从Firebase获取列表并将其拉入数组,以便我可以将其呈现给屏幕,然后使用reorderArray函数在移动项目后保持数组索引顺序在列表中。所以,如果我有一系列歌曲...我会称之为songList(想想没有Firebase)并假设这是我的HTML:

<ion-list reorder="true" (ionItemReorder)="reorderItems($event)">
    <ion-item *ngFor="let song of songList; let i = index">
    {{i+1}}. {{song.title}} - {{song.artist}}
    </ion-item>
  </ion-list> 

然后我有标准功能来重新排序数组:

reorderItems(indexes) {        
    this.songList = reorderArray(this.songList, indexes);    
  };

将'reorderArray'添加到导入以启用此功能:

import { NavController, AlertController, reorderArray } from 'ionic-angular';

稍微调查一下后,我认为reorderArray函数会执行一些.splice命令来使索引在数组中移动。

快速使用Firebase列表替换我的阵列。查看第一篇文章中的所有上述代码...所有这些都可以使列表显示在HTML页面上。但是一旦reorderArray被触发,我就会抛出“拼接”错误。事实证明,此时Firebase列表是一个对象,而reorderArray需要一个数组。我从Youtube视频中获得了以下代码:

//Set up the songList array
    var x = this.afDatabase.list('/songs');
    x.snapshotChanges().subscribe(item => {
      this.songList = [];
      item.forEach(element => {        
        var y = element.payload.toJSON();
        y["fbKey"] = element.key;
        this.songList.push(y);
      })
    })

我会尽力解释这是做什么的。我将x设置为我的Firebase列表/歌曲的参考。我调用snapShotChanges()来获取我的列表值和密钥。然后我订阅列表来浏览这些项目。我将setList声明为数组。我遍历项目列表,我猜'有效载荷'是一个获取所有对象数据的特殊属性?我想我将所有对象数据转换为数组。我在列表中添加了一个新字段,所以我可以从字段中获取.key值?然后我将所有数据推送到一个数组中。

我再次不确定这些魔法是如何运作的,但确实如此。现在我在songList中有一个包含所有数据的数组......现在我可以使用reorderArray函数在重新排序后将索引保持在客户端。

但......新问题。 Firebase列表中没有该索引值的客户端表示。

这段代码的其余部分有点模糊,因为当事情开始工作时,我遍布地图并添加了许多东西以使其工作。现在我有Ionic Serve问题,如果没有将它部署到Firebase或Ionic View,就无法正常运行...所以我必须通过内存。

所以这是我的最终HTML的样子:

<ion-list reorder="true" (ionItemReorder)="reorderItems($event)">
    <ion-item *ngFor="let song of songList | orderBy: 'sortOrder'; let i = index">
    {{i+1}}. {{song.title}} - {{song.artist}} ({{song.sortOrder}})
    </ion-item>
  </ion-list>  

这里唯一真正的区别是我在一个名为sortOrder的新字段上有一个orderBy。

以下是这一切的工作原理:

reorderItems(indexes) {  
    var luTitle = '';
    var luArtist = '';

    this.songList = reorderArray(this.songList, indexes);

    this.songList.forEach( song => {
      this.afDatabase.database.ref('songs/' + song.fbKey + '/sortOrder').set(this.songList.indexOf(song));

      this.afDatabase.database.ref('songs/' + song.fbKey)
      .on('value', function(snapshot) {
        luTitle = snapshot.child('title').val();
        luArtist = snapshot.child('artist').val();
      })

      console.log("Index: " + this.songList.indexOf(song));      
//      console.log("Title: " + song.title);      
      console.log("LU Title: " + luTitle);      
      console.log("LU Artist: " + luArtist);      
      console.log("FB Key: " + song.fbKey);  
      console.log("Sort Order: " + song.sortOrder); 
    })  
  };

其中很多只是将内容记录到控制台,但真正的工作是:

我要做的第一件事是在this.songList上运行reorderArray,它会在客户端的正确位置获取所有索引。然后我遍历该数组中的所有项目,并使用我们在将初始FB列表转换为数组时设置的song.fbKey创建对FB列表的引用。然后我设置该歌曲的sortOrder字段等于该歌曲的当前索引,因为它在该时刻存在于客户端。我认为之后的其他所有内容都是我将内容记录到控制台以查看值。 LU(Look Up)的东西只是我弄清楚如何从Firebase中获取一个值。

现在,ngFor中的orderBy立即通过sortOrder字段对所有内容进行排序,该字段基本上来自FB。我不记得了,但我认为如果列表是全新的FB并且没有sortOrder字段但它默认按键排序...这很好......第一次重新排序时触发所有sortOrders得到设置

我确信当我回到这里时会发现一些错误......但是到目前为止它仍在运行。

感谢您阅读,如果你做到这一点。

ER