【问题标题】:Sort nested observable对嵌套的 observable 进行排序
【发布时间】:2018-01-28 19:59:02
【问题描述】:

我这里有一个 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[];
}

在我的服务文件中,我像这样读取文件(将其变成可观察的,因为我希望能够更改数据的顺序,并可能在以后添加/删除/更改问题):

getSurveyQuestion(): Observable<Test[]> {
    return this.http
        .get<Test[]>("/path/to/questions.json")
        .do(data => console.log("All : " + JSON.stringify(data)))
}

在控制台中,以上输出:

JS:全部:[{"question":"您的年龄范围是多少?,"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 中添加一个按钮或其他内容,点击它会调用一个函数来重新排列用户可以在屏幕上看到的项目。目前,仅按问题(按字母顺序、升序或降序)排列 observables 数组的东西就足够了。几个小时以来,我一直在尝试完成此任务,但我在 google(和 stackoverflow)上发现的任何内容都没有帮助我完成此任务。

你们中有人知道如何按照我正在寻找的方式对 observable 的数据进行排序/重新排列吗?

提前致谢。

(如果有帮助,我正在使用 NativeScript + Angular)。

【问题讨论】:

  • 我假设在某些时候您将问题数组存储在类的 propertyData 属性中。您粘贴的代码中没有显示。如果是这样,只需创建一些方法并使用 Array.sort 方法重新排序项目。然后从模板中调用这些方法。
  • 啊,是的,抱歉。我已经更新了这个问题。我一直在尝试使用array.sort,但我一定是用错了,因为我从来没有引用过这些问题。我以为我会像 this.propertyData.question 那样做,但这似乎行不通。

标签: typescript rxjs observable angular2-nativescript


【解决方案1】:

您可以使用 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);

在此处阅读有关BehaviorSubjects 的更多信息: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);
    })
  }

请注意,上面的代码是“草稿”形式,可能需要一些小的调整/编辑才能在您的程序中工作,但那里的方法将适用于您的用例。

【讨论】:

  • 如果这回答了您的问题或者您需要更多信息,请告诉我。
  • 非常感谢您的回答,我目前正在尝试在我的用例中实现它。考虑到我对很多东西都很陌生,因此这很棘手,因此需要很长时间才能解决某些问题。例如:我试着把sortFn$ = new BehaviorSubject&lt;SortFnType&gt;(alphabeticalSort) 给我一个错误&lt;SortFnType&gt;:(找不到名称'SortFnType')和alphabeticalSort:(找不到名称'alphabeticalSort')。可能是因为我遗漏了一些东西,但是这样的东西我需要很长时间才能弄清楚哈哈:)
  • 好吧,您需要自己实现“alphabeticalSort”,并自己定义SortFnTypealphabeticalSort 将与我的答案中显示的 reverseAlphabeticalSort 非常相似——我将把它留给你让那个工作:)。SortFnType 只是我为 Typescript 类型弥补的占位符。我会推荐阅读有关 Typescript 自定义类型的内容。现在,只需将 SortFnType 替换为 any 并稍后再担心。
  • 啊,好的,我明白了。我会玩一下这个。我会接受你的回答,因为它确实为我指明了一个我自己永远也想不通的方向。如果我在数小时的努力之后仍然没有得到它,我总是可以提出一个新问题。非常感谢您的宝贵时间! :)
  • 乐于助人 :) -- 不要对自己太苛刻。有耐心,如果你继续努力,你最终会得到它。你在正确的轨道上!请随时查看我的个人资料并与我联系以解决未来的问题。
猜你喜欢
  • 2019-06-25
  • 1970-01-01
  • 2013-02-06
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多