"Improve your Angular ngrx workflow by utilizing the sandbox pattern to steer clear of

Currently, I'm trying to determine whether my implementation of the ngrx and sandbox pattern is effective. Here's the issue I'm facing:

getFiles(userId: number, companyId: number) {
  this.fileService.getFiles(userId, companyId).subscribe(res => this.store.dispatch(myaction({files: res})))
}

This function involves calling a service and handling the success through an action dispatch.

In order to call the sandbox function, I need to utilize two selectors in my container-component to retrieve userId (userId$) and companyId (company$), which are required parameters for the sandbox function. My ngOnInit looks like this:

combineLatest([this.company$, this.userId$])
  .pipe(
    filter(res => res[0] !== null && res[1] !== null),
    take(1),
    map(res => {
      let companyId = res[0].id;
      let userId = res[1];
      this.sandbox.getfiles(companyId, userId);
    })
   
  )
  .subscribe();

I'm unsure if this is the right approach or if it leads to nested subscriptions. The challenge arises when I try to avoid subscribing inside the function declaration while still requiring data from the selectors before invoking the sandbox function. What is the recommended solution?

Answer №1

By relocating the nested subscription to a separate method, you are not really resolving the issue but simply shifting it around.

In the scenario you presented, employing a flattening operator in conjunction with tap could be beneficial.

In your specific situation:

sandbox.service.ts

getFiles(userId: number, companyId: number) {
  return this.fileService.getFiles(userId, companyId).pipe(
    tap(res => this.store.dispatch(myaction({files: res}))
  )
}

some.container.ts

combineLatest([this.company$, this.userId$])
  .pipe(
    filter(res => res[0] !== null && res[1] !== null),
    take(1),
    switchMap(res => {
      let companyId = res[0].id;
      let userId = res[1];
      return this.sandbox.getFiles(userId, companyId);
    })
   
  )
  .subscribe();

This way, you only need to manage one subscription. To delve deeper into flattening operators (switchMap, mergeMap, concatMap, etc.), refer to this.

PS. Following @gunnar-b's suggestion, consider exploring effects and how to effectively implement them, as it appears you may not be fully utilizing ngrx.

Answer №2

It is generally not recommended to manually manage a subscription within your NGRX app code as it can lead to memory leaks if not handled properly when the component goes out of scope.

In most cases, Observables should be consumed using either the async pipe in components or through @ngrx/effects for handling side effects from actions.

#1 Utilizing the async pipe:

A component can create an Observable field and set it up on initialization:

public titleUppercase$: Observable<string>

ngOnInit(): void {
    this.titleUppercase$ = this.store.pipe(select(titleSelector)).map(title => title.toUpperCase());
}
<p>{{titleUppercase$ | async}}</p>

Angular automatically manages the subscription in this setup, eliminating the risk of memory leaks.

If the logic of the pipe becomes complex, it's recommended to extract it to a Service class for better testability.

#2 Using @ngrx/effects:

Effects are designed to handle "side effects," such as asynchronous processes that do not directly modify the Store state. For example, making an HttpClient call to fetch data from a server constitutes a side effect.

Refer to the user guide for @ngrx/effects library at:

Here's an example of an effect that loads data from the server based on a user action:

// Code snippet demonstrating @ngrx/effects usage

By following this approach, your app components can observe state changes to render content and trigger actions when necessary. Complex business logic can be managed efficiently using reducer functions and effects, simplifying unit testing of your UI application.

For cases where multiple effects share similar requirements, consider implementing a common injectable dependency or base class. This can streamline the process and improve overall code reuse.

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

When trying to install my npm package from the registry, I keep encountering an issue despite being able to install it locally

I recently released my Node.js/typescript package on the npm registry, but I'm encountering issues when trying to install it from there. Oddly enough, local installation works perfectly fine. Here's the output from the local installation: $ npm ...

Password validation with Mongoose customization

I'm working on creating a Schema using mongoose, but I'm facing some challenges when it comes to implementing custom validation for the password. The password should meet the following criteria: It must contain at least one special character ...

Sorting table by priority in HTML is not functioning as expected

I am currently developing this code for a SharePoint 2010 platform. While the table can currently be sorted alphabetically, I am looking to implement a different functionality. Unfortunately, I am facing an issue with changing variables 'a' and ...

Surprising Logging Quirks in Angular

I've encountered a perplexing issue in my Angular app where an array is logged before adding an element to it, yet the log shows the updated array with the added element. This array is then utilized in an HTML file with ngFor. component.ts file inter ...

Merge nested arrays while eliminating any redundant elements

Is there a way to merge these array sets while ensuring that duplicate values are removed? I am unsure if lodash provides a solution for this specific scenario where the arrays are nested. Most of the solutions I have come across assume flat arrays. Any ...

React form events onSubmit and onClick fail to trigger within Zurb Foundation's 'Reveal' modal dialog

Since upgrading from React 16.12.0 to React 17.0.0, I've encountered an issue with my code. Previously, everything worked perfectly fine, but now none of my events seem to be firing (meaning the console.log statement never appears). class MyClass exte ...

Reconnecting the bone: A guide to reestablishing the mesh skeleton in Three.js after rebind

I am facing a challenge where I need to independently rotate bones on a rigged hand mesh along the global axis using direction vectors to calculate their orientation. To tackle this, I have developed the following code: function boneLookAtLocal(bone, posit ...

Issue with deep linking functionality on S3 storage service turning out to be

After successfully deploying my angular5 app to: http://myApp.s3domain.amazonaws.com The Angular router is automatically directing me to http://myApp.s3domain.amazonaws.com/home However, when I try to access a link with a unique parameter like so: http:/ ...

Trap mistakes while utilizing async/await

Within my Express application, I have a register function for creating new users. This function involves creating the user in Auth0, sending an email, and responding to the client. I am looking to handle errors from Auth0 or Postmark individually and send ...

Challenges with synchronizing the scope of global arrays when reading JSON files into objects

I'm attempting to load a JSON file into a global array of objects. The code appears to be functioning correctly, however, I am encountering difficulty extracting the data from the Ajax $.getJSON call and storing it in the global variable. This issue c ...

Inspecting tRPC routing for examination purposes

Introduction Within my API, it is essential to authenticate the caller following input validation. The authorization for certain endpoints relies on details provided in the input parameters, such as the specific server-side resource being accessed and the ...

One Background Image Serving Multiple Divs

Can you use one image (PNG or SVG) as the background for multiple divs? Take a look at the images below to see how it could work. And if the screen width gets smaller and the divs stack up vertically, is there a way to change the background accordingly? D ...

Angular Test Error: Refactoring requires a source file to be present

Trying to execute the command ng test, I encountered an error message. How can this issue be resolved? I am unsure of its meaning. ERROR in Must have a source file to refactor. To eliminate this warning, use "ng config -g cli.warnings.versionMismatc ...

Multiplication cannot be performed on operands of type 'NoneType'

Hello everyone, I am attempting to calculate the unit price and quantity from this table using the following model: class Marketers(models.Model): category =models.ForeignKey(Category, on_delete=models.CASCADE, null=True) name =models.CharField(max ...

Is there a problem with the string comparison in my JavaScript code?

I am dealing with various XML files specific to different operating systems. Here is an excerpt from the SunOS XML: <osname>SunOS </osname> This data is extracted using jQuery: var osname = $(this).find('osname').text(); However ...

Guide to implementing a Page Object Model for improved debugging of Protractor tests

Introduction I am on a mission to streamline my e2e testing code using the Page Object Model for easier maintenance and debugging. My Approach When embarking on creating end-to-end tests with Protractor, I follow these steps to implement the Page Object ...

In my experience, the GET request is functioning properly within Postman, but for some reason the POST method continues to send requests repeatedly

ISSUE: I am encountering a problem while making a POST request in Postman. The application keeps sending requests without receiving any response. I have read through various solutions for Postman hanging during a POST request, but none of them seem to sol ...

Sending blank AJAX data to a PHP function

I am facing a challenge where I need to utilize AJAX to send the ID of an element and a specific value (1,2,3) to a PHP document for validation. Despite successfully logging both values in the console, the PHP file always returns that the data is empty. ...

Is there a way for me to include .js or .cpp prior to using the Vim shortcut key gf?

When using a programming language like nodejs, the require function does not require the addition of the .js extension. For example: var Assert = require('./app_base'); However, in vim, when using gf, it cannot find app_base without the .js ext ...

Create a new CSS rule within a class, and remember to save the changes to

Upon opening page 1.html, I utilize JavaScript to dynamically add a background image to the body of the page. To achieve this, I use the following code: document.body.style.backgroundImage = "url(http://www.example.com/image.jpg)"; This code effectively ...