In Rxjs, ConcatMap doesn't get executed

I am currently developing a file upload component that involves checking for the existence of a file before proceeding with the upload process. If the file already exists, the user is given the option to either save as a copy or overwrite the existing file. In cases where the user chooses to save as a copy, the existence check needs to be repeated recursively. This could lead to multiple observables being chained and executed sequentially.

However, I encountered a bug where the observable returned in the expression-function is not being executed, even though it is chained using the concatMap pipe.

I'm puzzled by this unexpected behavior. Can anyone shed light on why this is happening?

The relevant code snippet is shown below:

  onDocumentsUploaded(documents: CustomDocument[]) {
    console.log(documents)
    documents = documents.map(document => {
      return {
        ...document,
        fullName: document.name + "." + document.extension
      }
    });

    for (let document of documents) {
      this.sub.add(
        this.handleUpload(document).subscribe()
      );
    }
  }

  private handleUpload(document: CustomDocument): Observable<CustomDocument[]> {
    return this.documentService.checkIfExists(document).pipe(
      concatMap(exists => this.expression(document, exists))
    );
  }

  private expression(document: CustomDocument, exists: boolean): Observable<CustomDocument[]> {
    let subject$ = new Subject<CustomDocument[]>();
    if (exists) {
      this.confirmationService.confirm({
        header: this.translate.instant("documentUpload.confirmation.header"),
        message: this.translate.instant("documentUpload.confirmation.message", { fileName: "'" + document.fullName + "'" }),
        icon: 'pi pi-info-circle',
        accept: () => {
          subject$.pipe(
            concatMap(_ => this.handleUpload({
              ...document,
              name: document.name + " (Copy)",
              fullName: document.name + "(Copy)" + "." + document.extension
            }).pipe(
              tap(x => console.log("handleUpload"))
            ))
          );
        },
        reject: () => {
          subject$.pipe(
            concatMap(_ => this.documentService.upload(document))
          );
        }
      });
      return subject$.asObservable();
    }
    else {
      return this.documentService.upload(document);
    }
  }

Answer №1

When you pass a function to the accept method, it seems that you are sending the subject$ through the concatMap, but ultimately not using the resulting observable.

It's important to remember that calling .pipe() does not alter the original observable (or subject), but instead creates a new observable with the specified operators.

To achieve your desired outcome, consider returning the result of subject$.pipe(...) rather than subject$.asObservable().

Answer №2

After taking into consideration your observation that the confirmationService.confirm function is thread blocking, it seems that employing the Subject in this scenario is redundant.

Instead of using the Subject, you can implement a solution like the one below.

private handleUpload(document: CustomDocument): Observable<CustomDocument> {
  return this.documentService.checkIfExists(document).pipe(
    concatMap((exists) => 
      exists
      ? this.confirmAction(document) 
      : this.documentService.upload(document)
    )
  );
}

private confirmAction(document: CustomDocument): Observable<CustomDocument> {
  let action$: Observable<CustomDocument>; 

  this.confirmationService.confirm({
    header: this.translate.instant("documentUpload.confirmation.header"),
    message: this.translate.instant("documentUpload.confirmation.message", { fileName: "'" + document.fullName + "'" }),
    icon: 'pi pi-info-circle',
    accept: () => {
      action$ = this.handleUpload({
        ...document,
        name: document.name + " (Copy)",
        fullName: document.name + "(Copy)" + "." + document.extension
      })
    },
    reject: () => {
      action$ = this.documentService.upload(document))
    }
  }  
    
  return action$; 
}

By the way, attempting to use the Subject led to complications due to two main issues.

  1. As noted by @kszksz, utilizing subject$.pipe() does not alter the original subject$; it generates a new observable instead.
  2. To trigger a notification within a Subject, you must call its method next with the value (e.g., subject$.next(value)).

In this case, however, incorporating the Subject unnecessarily complicates the code without providing any real benefits.

Cheers

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Implementing a Typescript hook using useContext along with an uninitialized context object

I am currently attempting to develop a custom hook called useAuth in React 17 with TypeScript. While my solution is somewhat functioning, it requires the following syntax when utilizing the hook methods: const auth = useAuth(); // Do other stuff ...

Challenge Encountered while Generating Angular Docker Image using VSTS Pipeline

I'm currently in the process of setting up a VSTS pipeline to create a Docker Image for an Angular Application. I've chosen the "Hosted Windows Container" as the Agent pool, but I'm encountering the following error: Step 1/5: FROM nginx:alp ...

In Typescript, what sets apart a generic written before a function compared to after a type declaration?

Can you explain the difference between these two type declarations for arrow functions? export type Sort = <D>(r: Rows<D>, f: Field<D>, o: Order) => Rows<D>; export type Sort<D> = (r: Rows<D>, f: Field<D>, o: ...

Ways to dynamically generate a generic that expands a union class type

Reviewing the code snippet: const events = { a: ['event1' as const, 'event2' as const], b: ['event3' as const, 'event4' as const], }; class SomeClass< T extends AnotherClass<typeof events[keyof typeof ev ...

Having trouble importing the module in NestJS with Swagger?

Currently, I am in the process of developing a boilerplate NestJS application. My goal is to integrate @nestjs/swagger into the project. However, I have encountered an import error while trying to include the module. npm install --save @nestjs/<a href=" ...

The concept of Nested TypeScript Map Value Type

Similar to Nested Typescript Map Type, this case involves nesting on the "value" side. Typescript Playground const mapObjectObject: Map<string, string | Map<string, string>> = new Map(Object.entries({ "a": "b", &quo ...

The process of linking a Json response to a table

In my products.components.ts class, I am retrieving Json data into the variable this.Getdata. ngOnInit() { this._service.getProducts(this.baseUrl) .subscribe(data => { this.Getdata=data this.products=data alert(JSON.stringify(this.Getdata)); ...

Provide a boolean value of true or false to indicate whether all delete operations were successfully completed

Currently, I am using Sequelize, GraphQL, and Typescript for my coding. Within my database, I have two tables named RecordInformation and OtherDescription. The RecordInformation table contains a foreign key called "OtherID" which references the OtherDescri ...

Optimizing Angular 2+ performance with a custom minification of the

I've taken note of the cautions regarding avoiding pipes for ordering/sorting. While I understand the concerns with impure pipes, I'm not entirely clear on the issue with minification. The documentation and various posts highlight the potential ...

The Angular application encountered errors while trying to resolve main.ts, polyfile.test, and style.css

I encountered an issue while trying to run my Angular app in a Docker container. Here are the steps I followed: 1) Installed npm (v.3.5.2), node (v. 12.15.0), and angular CLI (v. 9.0.1) on my local machine 2) Created an Angular project locally using the ...

An object resulting from the combination of two separate objects

After reading a helpful solution on StackOverflow about merging properties of JavaScript objects dynamically, I learned how to utilize the spread operator in Typescript. However, one question still remains unanswered - what will be the type of the object c ...

When attempting to navigate using router.navigate in Angular 6 from a different component, it triggers a refresh

My routing setup is structured as follows: Main App-routing module const routes: Routes = [ { path: '', redirectTo: environment.devRedirect, pathMatch: 'full', canActivate: [AuthenticationGuard] }, { path: &a ...

NextAuth is failing to create a session token for the Credential provider

Currently, I am in the process of developing an application using the t3 stack and am facing a challenge with implementing the credential provider from nextauth. Whenever I attempt to log a user in, I encounter an error in the console displaying the messag ...

Can browser-sync be used to update sass/css for angular 2 components through injection?

Currently, I am using browser-sync to dynamically inject and modify the CSS in my application's root stylesheets that are not directly managed by Angular. Surprisingly, this process does not require a reload. However, I have noticed that any changes ...

Utilizing ngModel within a nested ngFor loop in Angular to capture changing values dynamically

I have been working on developing a screen using Angular and I'm facing an issue with binding values using ngModel. https://i.sstatic.net/DCJ3T.png Here is my implementation. Any help would be appreciated. The model entity I am using for binding the ...

The error message "Property 'zip' is not available on the 'Observable' type in Angular 6" indicates that the zip property is not recognized by

I've been working with Angular 6 and I've also looked into using pipes, but I couldn't find the correct syntax for writing a zip function and importing it properly. Error: Property 'zip' does not exist on type 'typeof Observ ...

Transmit information through a router connection

When attempting to pass data from one page to another routing page using [queryParams]="{'usd':usd, 'count' :country, 'name' :name}" through the routing button, it works perfectly fine but an error is displayed in my console. ...

Examining Angular tests for window.location.href changes

authenticate() { const url = environment.authenticationEndpoint; window.location.href = url + '/login'; } I have an Angular service file containing the above code which redirects to the login URL. In order to unit test this, I added the foll ...

Is there a way to make a model behave like an object in loopback when typing?

One of the challenges I face is dealing with a loopback model that is often represented in raw JSON format. For example: @model() class SomeModel extends Entity { @property({ type: 'string' }) id?: string; } In its raw JSON form, it would l ...

Guide to inserting an Angular routerLink within a cell in ag-Grid

When attempting to display a link on a basic HTML page, the code looks like this: <a [routerLink]="['/leverance/detail', 13]">A new link</a> However, when trying to render it within an ag-Grid, the approach is as follows: src\ ...