【问题标题】:Angular/RxJs: how to retrieve specific value from key-value pair from array in ObservableAngular/RxJs:如何从 Observable 中的数组中的键值对中检索特定值
【发布时间】:2021-11-22 17:30:15
【问题描述】:

这里是简化的demo

有没有一种简单的方法可以在模板中打印来自Array 的特定元素的值在Observable 中?问题是我有一个键值对列表,其中键具有一些特定的结构,并且每个键之间的它们可能不同。而且我想知道是否有任何方法可以创建某种转换器到对象,其中字段将是键的文字。或者有没有很好的解决方案通过传递键来检索值,但是它可以在模板和组件上使用。因此,例如直接从labels$ 中提取给定键的值。

在给定的演示中,我有方法filterLabels(key: string),当我在组件中使用它时效果很好。但这会导致每个标签等都有很多变量。当我尝试从模板调用此方法时,它进入了无限循环...

免责声明:出于某种原因,json 不想在带有注释代码的 labels.service.ts 中下载,其中类似的代码适用于我的原始应用程序。

编辑:

demo

我试图将 json 减少到映射。但是不明白为什么它适用于console.log(mapAccumulator['labels.header.defaultTitle']);,并且不适用于模板<h1>{{ convertedLabels$['labels.header.defaultTitle'] | async }}</h1>

【问题讨论】:

  • convertedLabels$ 设置为可观察对象的原因是什么?
  • 所以我可以在模板的异步管道中使用它。至少我是这么想的。我仍然对这里的这种可观察的方法感到困惑......
  • 我在您提供的演示中添加了一半的代码审查来更新您的答案。干杯

标签: angular rxjs observable


【解决方案1】:

原答案

异步管道返回对象。

现在你正在尝试获取一个不存在的 observable 成员, 您应该从异步管道的结果中获取成员,如下所示:

<h1>{{ (convertedLabels$ | async)['labels.header.defaultTitle'] }}</h1>

或者使用提供默认值的三元:

<h1>{{ (convertedLabels$ | async) ? (convertedLabels$ | async)['labels.header.defaultTitle'] : 'Default' }}</h1>

更新

问题是您在 html 中使用来自异步调用的值。创建组件时尚未检索到此值,这就是为什么异步管道会失败一秒钟直到检索到该值。

您可以使用异步管道使用的初始值创建主题,直到您的调用检索到新值,然后将该新值推送到主题。

然后,您可以从该主题创建一个 observable,并使用 getter 在您的组件中使用它。

示例服务:

private labelsSubject = new BehaviorSubject<LabelPair[]>(this.defaultLabelPairArray)

get labels$() {
  return this.labelsSubject.asObservable()
}

constructor(private http: HttpClient) {}

getLabels() {
  this.http.get<LabelPair[]>('/assets/labels.json').subscribe(
    labelPair => this.labelsSubject.next(labelPair)
  )
}

这是您的Stackblitz 的经过审查和清理的版本。

另一种选择

您还可以使用定义的对象而不是映射,通过稍微更改可观察对象的映射来进行类型检查:

HTML:

<h1>{{ (convertedLabels$ | async) ? (convertedLabels$ | async)?.defaultTitle : 'Default' }}</h1>

对映射进行分类:

class Labels {
  defaultTitle: string;
  otherTitle: string;
  name: string;
}

convertedLabels$ = this.labelService.getLabels().pipe(
  map((m) =>
    m.reduce((mapAccumulator, obj) => {
      const keyParts = obj.key.split('.')
      const key = keyParts[keyParts.length - 1]
      mapAccumulator[key] = obj.value;
      return mapAccumulator;
    }, new Labels())
  )
);

还有一个Stackblitz

【讨论】:

  • 让我知道这是否有帮助,或者您是否需要我查看演示中的其他特定内容。干杯
  • 哦,我没想到。不幸的是,它不能很好地工作......首先它抛出一个错误ERROR Error: Cannot read properties of null (reading 'labels.header.defaultTitle'),然后它被正确加载。另外我想知道这是否是实现这一目标的最佳方法?以及如何正确更改标题?我需要这样做:&lt;h1&gt;{{ header$ | (convertedLabels$ | async)['labels.header.defaultTitle'] }}&lt;/h1&gt;?所以起初它会尝试加载未定义的header$ 然后defaultTitle。当我点击按钮更改标题时,它会首先加载header$
  • 哦,我的想法行不通。而且我知道缺少| 是一个错误。但它仍然无法像我想象的那样工作......
  • 但是你检查过控制台吗?因为它会引发此错误,然后正确加载标头。空检查的语法是否正确?它会破坏应用程序并在预览中显示该错误:Conditional expression requires all 3 expressions at the end of the expression
猜你喜欢
  • 2018-12-15
  • 2022-01-15
  • 2021-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-11-25
  • 2011-01-15
  • 2020-05-05
  • 1970-01-01
相关资源
最近更新 更多