简体   繁体   中英

How to return subscription and promise from single function in angular?

I am working on one angular project in which I have file upload feature is implemented. I have created one upload service and make one function inside it for upload file

service.ts :

upload(file: File){
  return new Promise(resolve=>{
    var file = file;
    bucket.upload(file).on("httpUplaodprogress", (progress)=>{
        const percent = progress.percent

        -->  Here I want to emit this percent value from this function. and want to get it where it is from called.


    }).send(response =>{
      response.error ? reject(response.err);
      resolve(response);
    })
  })
}

Now this upload service is used at many place.

Eg :

uploadComponent.ts :

progress:number = 0;

constructor(private uploadService: UploadService) {}

handleFileInput(file){
    this.uploadService.upload(file).then(result=>{
       result ? show success msg for file uplaod success : show error

       ==> I want to subscribe service's upload function's progress variable 
           here for assign that value into this host component's progress variable which is 
           bind with progressbar copmponent.
   
    })
}

uploadComponent.html

<progressbar [progress]="progress" />

This is current scenario where we can't access progress variable from service function into host component where service function is called.

one way is that, we can get subscribe service function into host component and can progress value can continuously get. but how ?

because service function already return promise. how can I use subscription inside promise and subscribe it into host component.

I had also thought about global subscription variable into service and subscribe it into host component. but it can cause problem when upload file from multiple places and show progressbar.

I want to keep subscription variable's scope local for each call.

If anyone know about it, how to broadcast value from promise function and receive at host function from where it is called.. then please reply this. It's very helpful for me.

Your should return an Observable from your service instead of a Promise.

UploadService

// note that BucketUploadResponse is an interface I made up
upload(file: File): Promise<BucketUploadResponse> {
     // delegate to our Observable implementation and convert to promise
     return this.upload$(file).toPromise();
}

// note that BucketUploadResponse is an interface I made up
upload$(file: File): Observable<number | BucketUploadResponse> {
        return new Observable<number>((subscriber) => {
            bucket
                .upload(file)
                .on('httpUplaodprogress', (progress) => {
                    const percent = progress.percent;
                    // emit progress
                    subscriber.next(percent);
                })
                .send((response) => {
                    if (response.error) {
                        // error out
                        subscriber.error(response.error);
                    } else {
                        // emit response as last item to keep old contract
                        subscriber.next(response);
                        subscriber.complete();
                    }
                });

            return () => {
                // called when no subscription is left. You could abort the upload here for example
            };
        });
    }

In the consuming component, you can subscribe to the Observable:

    progress:number = 0;
    
    private uploadSubscription?: Subscription;

    constructor(private uploadService: UploadService) {}

    handleFileInput(file){
        this.progress = 0;
        // unsubscribe from an existing upload
        this.uploadSubscription?.unsubscribe();
        this.uploadSubscription = this.uploadService.upload(file).subscribe((progress) => {
            if (typeof progress === 'number') {
                this.progress = progress;
            } else {
                // handle BucketUploadResponse if required
            }
        }, () => {
            // complete, show success message
        }, (error) => {
            // error, show error message
        })
    }

You can pass headers to you http call to subscribe progress

reportProgress: true,
observe: 'events'

In you Upload Component

yourservice.subscribe((e: HttpEvent<any>) => {
          switch (e.type) {
            case HttpEventType.Sent:
              break;
            case HttpEventType.ResponseHeader:
              break;
            case HttpEventType.UploadProgress:
              this.progress = Math.round(e.loaded / e.total * 100);
              break;
            case HttpEventType.Response:
              this.progress = -1;
          }
    });

OR

You have an option to implement a behavior subject to achieve this if you want In your service.ts declare processPercentage as behavior subject

const percent = progress.percent;
this.processPercentage.next(percent);

In your uploadComponent.ts

subscription:Subscription;
constructor(private uploadService: UploadService,private service:Service) {}
ngOnInit(){
 this.getProgress();
}

getProgress(){
 this.subscription = 
 this.service.processPercentage.asObservable().susbcribe((progress) => {
  this.progress = progress;
  console.log(this.progress);
  // You can bind to your progressbar from here 
 });
}

ngOnDestroy(){
 this.subscription.unsubscribe();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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