嵌套嵌套可观察 [英] Sort nested observable

查看:106
本文介绍了嵌套嵌套可观察的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我这里有一个看起来像这样的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 BehaviorSubjects 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆