嵌套嵌套可观察 [英] Sort nested observable
问题描述
我这里有一个看起来像这样的JSON文件:
I have here a JSON file which looks like this:
[
{
"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"]
}
]
在我的项目中,我有一个具有相同结构的模型,如下所示:
In my project I've got a model with the same structure which looks like this:
export interface Test {
question: string;
options: string[];
}
在我的服务文件中,我这样读取文件(将其变成可观察的文件,因为我希望能够更改数据的顺序,并可能以后再添加/删除/更改问题):
in my service file, I read the file like so (turning it into an observable, because I want to be able to change the order of the data and possibly later add/remove/change questions):
getSurveyQuestion(): Observable<Test[]> {
return this.http
.get<Test[]>("/path/to/questions.json")
.do(data => console.log("All : " + JSON.stringify(data)))
}
在控制台中,以上输出:
In the console, the above outputs:
JS:全部:[{"question":您的年龄范围是多少?""options":["10-20","20-30","30-40","40-50"] },{//.....}]
JS: All : [{"question":"What is your age range?,"options":["10-20","20-30","30-40","40-50"]}, { //.....}]
我的组件文件如下所示:
My component file looks as follows:
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中,我将其输出到屏幕上,如下所示:
In my html, I output it to the screen like so:
<StackLayout *ngFor="let item of propertyData">
<Label text="{{item.question}}"></label>
</StackLayout>
现在,我想向html中添加按钮或其他内容,点击该按钮将调用一个函数,以重新排列用户在屏幕上可以看到的项目.目前,只需按问题(按字母顺序,升序或降序)排列可观察对象的数组就足够了.我已经尝试了几个小时了,但是我在Google(和stackoverflow)上发现的任何内容都没有帮助我实现这一目标.
now, I want to add a button or something to the html, which on tap calls a function to rearrange the items the user can see on screen. For now, something that simply arranges the array of observables by question (alphabetically, ascending or descending) is good enough. I've been trying to accomplish this for hours, but nothing I found on google (and stackoverflow) has helped me accomplish this yet.
你们中的任何人都知道如何按照我寻找的方式对可观察对象的数据进行排序/重新排列吗?
Does any of you know how to sort/rearrange the data of an observable in the way I'm looking for?
谢谢.
(如果有帮助,我正在使用NativeScript + Angular).
(in case it helps, I'm working with NativeScript + Angular).
推荐答案
您可以使用Observable map
运算符对列表进行排序.
You can use the Observable map
operator to sort the list.
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;
});
}
现在,关于在单击按钮时更改它们的排序方式的问题,这有点棘手.您将要使用于排序的函数异步.您可以通过在组件上创建属性来做到这一点:
Now as for the question of changing the way they are sorted when you click a button, that's a bit trickier. You will want to make the function being used for sorting asynchronous. You could do that by making a property on your component:
sortFn$ = new BehaviorSubject<SortFnType>(alphabeticalSort // or whatever default sort you want);
在此处了解有关BehaviorSubject
的更多信息: http://reactivex.io/rxjs/manual/overview.html#behaviorsubject
Read more about BehaviorSubject
s here: http://reactivex.io/rxjs/manual/overview.html#behaviorsubject
然后,当单击该按钮时,next
将对该BehaviorSubject
起作用.
Then next
functions to that BehaviorSubject
when the button is clicked.
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
使其进入您的视频流.
And then use combineLatest
to get it into your stream.
ngOnInit() {
this.testService.getSurveyQuestion()
.combineLatest(this.sortFn$)
.map(([data, sortFn]: [Test[], SortFnType]) => {
return data.sort(sortFn);
})
.subscribe(data => {
this.propertyData = data;
});
}
此外,我建议使用async
管道将您的数据传递到模板中,这样您就不必搞砸订阅清理了.
Also, I'd recommend using the async
pipe to pass your data into your template so you don't have to mess with Subscription cleanup.
<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);
})
}
请注意,上面的代码为草稿"格式,可能需要进行一些细微的调整/编辑才能在您的程序中使用,但是此处的方法将适用于您的用例.
Note that the code above is in "rough draft" form and will probably require some minor tweaks / edits to work in your program, but the approach there will work for your use case.
这篇关于嵌套嵌套可观察的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!