简体   繁体   English

使用 rxjs 在 angular 中发送多个 post 请求

[英]Send multiple post request in angular using rxjs

I have a form where I take name as input and count(number).我有一个表格,我将名字作为输入和计数(数字)。

I want to append the number to the name.我想把 append 这个号码给名字。 For eg.例如。

if user enters worker and count 5. I want to append the number starting from 1 until the count ie 5 and it will be like worker-1, worker-2, worker-3, worker-4, worker-5.如果用户输入工人并计数 5。我想 append 从 1 到计数即 5 的数字,它将像工人 1、工人 2、工人 3、工人 4、工人 5。

I want to then send multiple requests to the server to add these workers in the database.然后我想向服务器发送多个请求以将这些工作人员添加到数据库中。

I am doing something like this currently.我目前正在做这样的事情。

addItems() {

    for (let i = 1; i <= this.count; i++) {
        body.name = this.createItemForm.get('name').value + '-' + i;
        this.add(body);
      }

 }

add(body: formBody) {
    this.cvmService.createServer(body).subscribe(() => {
      this.alertify.success('New item was successfully created');
      this.close(true);
    }, error => {
      this.alertify.error('\n' + error);
    });
  }

My question is how can I do it with rxjs and which is the best operator to do it.我的问题是如何使用 rxjs 做到这一点,这是最好的操作员。 Especially the part where I call add() inside for loop, is there a better way to do it?特别是我在 for 循环中调用 add() 的部分,有更好的方法吗?

generate is your friend: generate是你的朋友:

const baseName = this.createItemForm.get('name').value + '-';

generate(1, x => x <= this.count, x => ++x).pipe(
  map(val => baseName + val),
).subscribe(bodyName => {
 // do something with your worker-1 .... worker-count
});

generate will generate sequence from 1 up to your input count. generate将生成从 1 到您的输入计数的序列。

map will just concat your prefix (eg 'worker') with the number to produce bodyName . map只会将您的前缀(例如“工人”)与生成的数字连接bodyName

...and then it is up to you. ......然后由你决定。 It is not clear from the code what your body object looks like and what action/s you want to do with each request and what action in the end.从代码中不清楚你的身体 object 是什么样的,你想对每个请求执行什么操作以及最终执行什么操作。

Simply use range operator, it accepts two parameters;只需使用范围运算符,它接受两个参数; start & count ( range(start: number, count: number): Observable ) and returns an Observable that emits a sequence of numbers which you can transform according to your need. start & count ( range(start: number, count: number): Observable ) 并返回一个 Observable ,它发出一个数字序列,您可以根据需要对其进行转换。

Consider the following example:考虑以下示例:

interface Body {
  name: string
}

class Component {
  constructor(
    private alertify: Alertify,
    private cvmService: CvmService
  ) { }

  public addMany(count: number, base: string): void {
    return range(1, count).pipe(

     /**
      * transform each emitted number into a @Body
      */

      map(number => { 
        const body: Body = { name: `${base}${number}` };
        return body;
      }),

      toArray(), // <-- collect emitted values

     /**
      * transform the array of @Body[] returned by @toArray() into an 
      * array of Observables and use @forkJoik operator to wait for all
      * Observables to complete
      */

      switchMap(array => forkJoin(array.map(body => this.addOne(body))))
    ).subscribe(() => console.log("done!"))
  }


  /**
  * transform each body into an Observable 
  * without subscribing to it
  * use @tap operator to listen for events that will be raised
  * by future subscriptions
  */

  public addOne(body: Body): Observable<void> {
    return this.cvmService.createServer(body)
      .pipe(
        tap({
          next: () => this.alertify.success('New item was successfully created'),
          error: error => this.alertify.error('\n' + error)
        })
      )
  }
}

Try this.尝试这个。 For example:例如:

forkJoin([res1, res2, res3, res4, res5])
.pipe(map(data => data.reduce((result,arr)=>[...result,...arr],[])))
.subscribe(data =>{

  this.autoCompleteValues = data;
  console.log(this.autoCompleteValues);
});

mergeMap to Turn Values into Subscribed Observables mergeMap将值转换为订阅的 Observables

mergeMap(value => observable) will subscribe and emit the value of the mapped observables for you. mergeMap(value => observable) 将为您订阅并发出映射的 observable 的值。 It looks like all you need is mergeMap(body => service(body)) and you're off to the races.看起来您只需要 mergeMap(body => service(body)) 就可以参加比赛了。


The following is a pretty direct translation of what you're doing with RxJS.以下是您使用 RxJS 所做的非常直接的翻译。 If your code works, then (in theory, I can't test it) this or something very similar should work.如果您的代码有效,那么(理论上,我无法测试它)这个或非常类似的东西应该可以工作。

I'm not sure where body is defined in your example, so I'll pretend it's an object with some properties and you're adding another property ( name ) to it我不确定body在您的示例中定义的位置,所以我假设它是一个具有一些属性的 object 并且您正在向它添加另一个属性( name

addItems(){
  
  range(1, this.count).pipe(
    map(i => ({
      ...body,
      name: `${this.createItemForm.get('name').value}-${i}`
    })),
    mergeMap(body => this.cvmService.createServer(body))
  ).subscribe({
    next: resp => {
      this.alertify.success('New item was successfully created');
      this.close(true);
    },
    error: err => this.alertify.error('\n' + err),
    complete: () => console.log(`${this.count} items where succesfully created`)
  });
  
}

forkJoin to Turn Array of Observables into Array of Responses forkJoin将 Observable 数组转换为响应数组

The same thing can be done with forkJoin since it looks like your service calls emit once and complete.使用forkJoin可以完成同样的事情,因为看起来您的服务调用发出一次并完成。

Here, you first need to create an array of the service calls you want.在这里,您首先需要创建所需的服务调用数组。 I do this by mapping an array [1,2,3,4,5] into body objects [{name:worker-1},{name:worker-2},{name:worker-3},{name:worker-4},{name:worker-5}] and then mapping body objects into service calls [observable,observable,observable,observable,observable] .我通过将数组[1,2,3,4,5]映射到主体对象[{name:worker-1},{name:worker-2},{name:worker-3},{name:worker-4},{name:worker-5}]然后将主体对象映射到服务调用[observable,observable,observable,observable,observable]

All that is done without any RxJS, the RxJS part is the forkJoin([observable,observable,...]) .所有这一切都是在没有任何 RxJS 的情况下完成的,RxJS 部分是forkJoin([observable,observable,...]) Which subscribes to every observables and wait for them all to complete.它订阅每个 observables 并等待它们全部完成。

The difference is that forkJoin will emit the final results as an array.不同之处在于 forkJoin 会将最终结果作为数组发出。 If you still want an alert and a call to this.close(true) for each result, then we'd need to instrument each service call (source observable in the array) to do that.如果您仍然希望为每个结果发出警报并调用 this.close(true),那么我们需要检测每个服务调用(数组中的可观察源)来执行此操作。

When you subscribe, the next callback will be given an array.当您订阅时, next回调将获得一个数组。 The implementation looks like this:实现如下所示:

addItems(){
  
  forkJoin(
    Array.from(
      {length: this.count}, 
      (_,i) => i+1
    ).map(i => ({
      ...body,
      name: `${this.createItemForm.get('name').value}-${i}`
    })).map(body => 
      this.cvmService.createServer(body).pipe(
        tap(_ => {
          this.alertify.success('New item was successfully created');
          this.close(true);
        })
      )
    )
  ).subscribe({
    next: resp => {
      console.log(`${resp.length} items where succesfully created`);
    },
    error: err => this.alertify.error('\n' + err)
  });
  
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM