对嵌套的可观察对象进行排序
Sort nested observable
我这里有一个 JSON 文件,如下所示:
[
{
"question": "What is your age range?",
"options": ["10-20","20-30","30-40","40-50"]
},
{
"question": "How did you find us?",
"options": ["Friend recommendation","Google","Other"]
},
{
"question": "Are you interested in etcetc?",
"options": ["No","Yes","Meh"]
}
]
在我的项目中,我有一个具有相同结构的模型,如下所示:
export interface Test {
question: string;
options: string[];
}
在我的服务文件中,我像这样读取文件(将其变成可观察的,因为我希望能够更改数据的顺序以及以后可能 add/remove/change 的问题):
getSurveyQuestion(): Observable<Test[]> {
return this.http
.get<Test[]>("/path/to/questions.json")
.do(data => console.log("All : " + JSON.stringify(data)))
}
在控制台中,以上输出:
JS: All : [{"question":"What is your age range?,"options":["10-20","20-30","30-40","40-50"]}, { //.....}]
我的组件文件如下所示:
export class TestComponent implements OnInit {
propertyData: Test[] = [];
constructor(private router: Router, private testService: TestService) {}
ngOnInit() {
this.testService.getSurveyQuestion().subscribe(data => {
this.propertyData = data;
}, err => {
console.log(err);
})
}
}
在我的html中,我是这样输出到屏幕上的:
<StackLayout *ngFor="let item of propertyData">
<Label text="{{item.question}}"></label>
</StackLayout>
现在,我想向 html 添加一个按钮或其他东西,点击它会调用一个函数来重新排列用户可以在屏幕上看到的项目。现在,简单地按问题(按字母顺序、升序或降序)排列可观察数组就足够了。几个小时以来,我一直在努力完成这项工作,但我在 google(和 Whosebug)上发现的任何东西都没有帮助我完成这项工作。
你们中有人知道如何以我正在寻找的方式 sort/rearrange 可观察数据吗?
提前致谢。
(如果有帮助,我正在使用 NativeScript + Angular)。
您可以使用 Observable map
运算符对列表进行排序。
ngOnInit() {
this.testService.getSurveyQuestion()
.map(data => {
return data.sort((a: Test, b: Test) => {
const aQ = test.question.toUpperCase();
const bQ = test.question.toUpperCase();
return aQ.localeCompare(bQ); // that will sort them alphabetically
));
})
.subscribe(data => {
this.propertyData = data;
});
}
现在关于在您单击按钮时更改它们的排序方式的问题,这有点棘手。您将希望使用于排序的函数异步。您可以通过在您的组件上制作 属性 来做到这一点:
sortFn$ = new BehaviorSubject<SortFnType>(alphabeticalSort // or whatever default sort you want);
在此处阅读有关 BehaviorSubject
的更多信息:http://reactivex.io/rxjs/manual/overview.html#behaviorsubject
然后 next
在单击按钮时作用于 BehaviorSubject
。
onClick() {
const reverseAlphabeticalSort = (a: Test, b: Test) => {
const aQ = test.question.toUpperCase();
const bQ = test.question.toUpperCase();
return bQ.localeCompare(aQ);
});
this.sortFn$.next(reverseAlphabeticalSort);
}
然后使用 combineLatest
将其添加到您的信息流中。
ngOnInit() {
this.testService.getSurveyQuestion()
.combineLatest(this.sortFn$)
.map(([data, sortFn]: [Test[], SortFnType]) => {
return data.sort(sortFn);
})
.subscribe(data => {
this.propertyData = data;
});
}
此外,我建议使用 async
管道将您的数据传递到您的模板中,这样您就不必搞乱订阅清理。
<StackLayout *ngFor="let item of sortedData$ | async">
<Label text="{{item.question}}"></label>
</StackLayout>
然后在你的组件中:
sortedData$: Observable<Test[]>;
ngOnInit() {
this.sortedData$ = this.testService.getSurveyQuestion()
.combineLatest(this.sortFn$)
.map(([data, sortFn]: [Test[], SortFnType]) => {
return data.sort(sortFn);
})
}
请注意,上面的代码采用 "rough draft" 形式,可能需要进行一些小的调整/编辑才能在您的程序中运行,但那里的方法适用于您的用例。
我这里有一个 JSON 文件,如下所示:
[
{
"question": "What is your age range?",
"options": ["10-20","20-30","30-40","40-50"]
},
{
"question": "How did you find us?",
"options": ["Friend recommendation","Google","Other"]
},
{
"question": "Are you interested in etcetc?",
"options": ["No","Yes","Meh"]
}
]
在我的项目中,我有一个具有相同结构的模型,如下所示:
export interface Test {
question: string;
options: string[];
}
在我的服务文件中,我像这样读取文件(将其变成可观察的,因为我希望能够更改数据的顺序以及以后可能 add/remove/change 的问题):
getSurveyQuestion(): Observable<Test[]> {
return this.http
.get<Test[]>("/path/to/questions.json")
.do(data => console.log("All : " + JSON.stringify(data)))
}
在控制台中,以上输出:
JS: All : [{"question":"What is your age range?,"options":["10-20","20-30","30-40","40-50"]}, { //.....}]
我的组件文件如下所示:
export class TestComponent implements OnInit {
propertyData: Test[] = [];
constructor(private router: Router, private testService: TestService) {}
ngOnInit() {
this.testService.getSurveyQuestion().subscribe(data => {
this.propertyData = data;
}, err => {
console.log(err);
})
}
}
在我的html中,我是这样输出到屏幕上的:
<StackLayout *ngFor="let item of propertyData">
<Label text="{{item.question}}"></label>
</StackLayout>
现在,我想向 html 添加一个按钮或其他东西,点击它会调用一个函数来重新排列用户可以在屏幕上看到的项目。现在,简单地按问题(按字母顺序、升序或降序)排列可观察数组就足够了。几个小时以来,我一直在努力完成这项工作,但我在 google(和 Whosebug)上发现的任何东西都没有帮助我完成这项工作。
你们中有人知道如何以我正在寻找的方式 sort/rearrange 可观察数据吗?
提前致谢。
(如果有帮助,我正在使用 NativeScript + Angular)。
您可以使用 Observable map
运算符对列表进行排序。
ngOnInit() {
this.testService.getSurveyQuestion()
.map(data => {
return data.sort((a: Test, b: Test) => {
const aQ = test.question.toUpperCase();
const bQ = test.question.toUpperCase();
return aQ.localeCompare(bQ); // that will sort them alphabetically
));
})
.subscribe(data => {
this.propertyData = data;
});
}
现在关于在您单击按钮时更改它们的排序方式的问题,这有点棘手。您将希望使用于排序的函数异步。您可以通过在您的组件上制作 属性 来做到这一点:
sortFn$ = new BehaviorSubject<SortFnType>(alphabeticalSort // or whatever default sort you want);
在此处阅读有关 BehaviorSubject
的更多信息:http://reactivex.io/rxjs/manual/overview.html#behaviorsubject
然后 next
在单击按钮时作用于 BehaviorSubject
。
onClick() {
const reverseAlphabeticalSort = (a: Test, b: Test) => {
const aQ = test.question.toUpperCase();
const bQ = test.question.toUpperCase();
return bQ.localeCompare(aQ);
});
this.sortFn$.next(reverseAlphabeticalSort);
}
然后使用 combineLatest
将其添加到您的信息流中。
ngOnInit() {
this.testService.getSurveyQuestion()
.combineLatest(this.sortFn$)
.map(([data, sortFn]: [Test[], SortFnType]) => {
return data.sort(sortFn);
})
.subscribe(data => {
this.propertyData = data;
});
}
此外,我建议使用 async
管道将您的数据传递到您的模板中,这样您就不必搞乱订阅清理。
<StackLayout *ngFor="let item of sortedData$ | async">
<Label text="{{item.question}}"></label>
</StackLayout>
然后在你的组件中:
sortedData$: Observable<Test[]>;
ngOnInit() {
this.sortedData$ = this.testService.getSurveyQuestion()
.combineLatest(this.sortFn$)
.map(([data, sortFn]: [Test[], SortFnType]) => {
return data.sort(sortFn);
})
}
请注意,上面的代码采用 "rough draft" 形式,可能需要进行一些小的调整/编辑才能在您的程序中运行,但那里的方法适用于您的用例。