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



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

我认为这可能与我定义"歌曲"的方式非常简单。我尝试了几种不同的方法...但在这一点上,我只是抓住稻草。

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

打字稿

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>

订阅Observablemap要推送到songs数组中的items。此外,使用生命周期挂钩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.
}
} 

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

当您尝试在不是数组的东西上执行函数时,会出现 array.splice 不是函数错误,在这种情况下,由于超出我理解的原因,可观察量似乎作为单个对象返回。

为了使事情正常工作,我分别声明了这些变量中的每一个:

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 循环照片阵列(没有异步管道)和从项目组调用的 reorderItem 函数与离子文档中的标准单行语法完美配合。

然后,为了更新 Firestore 集合中的索引,我从修改列表顺序后可见的按钮调用以下函数:

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

}

我应该注意的是,在添加新文档而不仅仅是 .add 时,我也总是使用 .createId() 方法,然后使用 .doc(newId).set({id:newId 等}),因为我发现这样做比使用 .snapshotChanges 和 map 函数而不仅仅是 .valueChanges() 要烦人得多 - 这就是为什么上述函数与所示语法一起使用的原因

另外,如果您在订阅之前不使用 rxjs take(1) 运算符,一开始一切看起来都很好,但是在 saveNewOrder 函数执行后,列表会重复几次

我回来晚了,但这是我试图解释我是如何让它工作的。
**警告 - 我是一个业余编码员,所以如果我解释使用错误的术语或我只是理解错误,我提前道歉。代码有效:)。

目标是使用新版本的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页面上。 但是一旦触发了重新排序数组,我就会抛出"拼接"错误。 事实证明,此时的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(查找)的东西只是我弄清楚如何从Firebase获得价值。

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

我敢肯定,当我回到这个时,我会发现一些错误......但到目前为止,它是工作代码。

感谢您的阅读,如果你做到了这一步。

最新更新