如何在订阅Angular 4中返回值

Posted

技术标签:

【中文标题】如何在订阅Angular 4中返回值【英文标题】:How to return value inside subscribe Angular 4 【发布时间】:2018-09-11 07:19:27 【问题描述】:

我是 angular 的 observables 新手。我有一个问题,我想在订阅方法中返回一个值。我有 以下方法(getFirebaseData(idForm:string):observable <any[]>):

getTotalQuestions(idForm:string)
let totalQuestions:number;
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => 
  
    items.map(item => 
      totalQuestions=item.Total;
      console.log(totalQuestions);
    );
  
);
console.log(totalQuestions);
return totalQuestions;

第一个console.log(totalQuestions) 打印4,但第二个console.log(totalQuestions) 打印undefined。 我知道订阅是一个异步操作,因此第二个console.log(totalQuestions)(“为了编写代码”)打印未定义,但在订阅方法完成后我找不到返回变量的方法。现在,如果我将订阅更改为地图:

getTotalQuestions(idForm:string)
let totalQuestions:number;
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => 
  
    items.map(item => 
      totalQuestions=item.Total;
      console.log(totalQuestions);
    );
  
);
console.log(totalQuestions);
return totalQuestions;

第一个console.log(totalQuestions) 不打印任何内容,第二个console.log(totalQuestions) 打印未定义。我不明白为什么会这样。

希望你能帮我澄清一下我不明白的概念。谢谢!

【问题讨论】:

请查看以下URL 【参考方案1】:

你不能像那样直接返回totalQuestions,你需要使用一个主题来实现。

getTotalQuestions(idForm:string): Observable<string> 
let totalQuestions:number;
var subject = new Subject<string>();
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => 
    items.map(item => 

      totalQuestions=item.Total;
      console.log(totalQuestions);
      subject.next(totalQuestions);
    );
  
);
  return subject.asObservable();

用法:getTotalQuestion(idForm).subscribe((r)=&gt;console.log(r))

【讨论】:

我们必须明白,我试图做的是一个反模式,不能强制异步任务同步,因此,包含 observable 的方法通常返回另一个 observable 或什么也不返回.因此,我接受这个答案作为解决方案。非常感谢! @Rajani Kanth 你能检查一下这个问题吗?和上面的问题一样! ***.com/questions/54873434/… 你是冠军!谢谢 谢谢!看起来很疯狂,对于所有 rxjs 方法,都没有像 angularjs 中的延迟承诺那样工作。不过这很好用。 @Rajani:它可以工作,但我想从服务而不是组件返回内部订阅数据,你能告诉我该怎么做吗?【参考方案2】:

Observable 在你订阅它时运行,订阅返回的总是一个订阅对象,比如 setInterval。第一个示例:因为这是一个异步调用,所以第二个 console.log 在执行之前不会等待订阅完成。

getTotalQuestions(idForm: string) 
  let totalQuestions: number;
  return this.getFirebaseData(idForm + "/Metadatos").pipe(
     map(items =>
      items.map(item => 
        totalQuestions = item.Total;
        console.log(totalQuestions);
      );
    ));


getTotalQuestions('231').subscribe(console.log)

【讨论】:

所以这里没有返回值?【参考方案3】:

I made a live example。 您无需触发订阅即可对数组进行转换或将某些对象减少为单个值,这是我的方法。 您的服务

getTotalQuestions(idForm: string): Observable<any> 
    return this.getFirebaseData(`$idForm/Metadatos`)
        .pipe(map(items => items
            .map(item => item.Total)
            .reduce((a, b) => a+b), 0));

您的组件

this.service.getTotalQuestions('id')
    .subscribe(totalQuestions => console.log(totalQuestions));

【讨论】:

【参考方案4】:

为了解决这个问题,我将创建一个属性 totalQuestions$ 一个 observable

在 TS 文件中

totalQuestions$ = this.getFirebaseData(idForm + "/Metadatos").pipe(
  map(items => items.reduce((prev, Total) => prev + Total), 0)))
)

现在你可以在你的模板中使用async pipe

<span> totalQuestions$ | async </span>

如果您想在 TS 文件中使用该变量,则可以使用组合运算符,如 forkJoin 或 combineLatest 来访问该值

newVariable$ = combineLatest([totalQuestions$, ...]).pipe(
  map(([totalQuestions, ... ]) => 
    // Perform an operation here and return a value
  )
)

【讨论】:

以上是关于如何在订阅Angular 4中返回值的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Angular 4+ 中取消/取消订阅所有挂起的 HTTP 请求

在使用带有 Angular 的 FromEvent RxJS 订阅输入标签值更改时如何避免使用“任何”?

Angular ngOnInit 如何将订阅结果用于另一个订阅/后端调用?

如何防止 Angular 中的多个订阅调用?

如何在 Angular 中返回可观察的模拟值

如何从 Angular 4 中的回调绑定