Leveraging Observables with ngrx for efficient async pipe implementation

Trying to create a shadow copy of pending changes using observables and ngrx has presented me with a puzzling issue:

export class SearchBoxContainerComponent {
    filterSettings$: Observable<FilterSettings>;
    filterChanges: {[key:string]: any};
    filterChanges$: Subject<{[key:string]: any}>;
    constructor(private store: Store<fromRoot.State>) {
        this.filterChanges = {};
        this.filterChanges$ = new Subject();
        this.filterSettings$ = Observable.combineLatest(
            store.let(fromRoot.getFilterSettings),
            this.filterChanges$,
            (filterSettings, filterChanges) => {
                return Object.assign({}, filterSettings, filterChanges);
            }
        );
        this.filterChanges$.subscribe(foo => {
            console.log('filterChanges$: ', foo);
        });
        this.filterSettings$.subscribe(foo => {
            console.log('filterSettings$: ', foo);
        });
        this.filterChanges$.next(this.filterChanges);
    }

    updateSetting(key, value) {
        this.filterChanges = Object.assign({}, this.filterChanges, {[key]: value});
        this.filterChanges$.next(this.filterChanges);
    }

    submitSearchbox() {
        // TODO send ngrx action to really update the filterSettings
    }
}

In this scenario, Observable.combineLatest is used instead of directly getting the observable from the ngrx store.

this.filterSettings$ = store.let(fromRoot.getFilterSettings); 

The issue arises when the search box initially opens with all values set to null. Only after updating a value do they get populated. Using store.let directly seems to solve this problem.

An async pipe is utilized in the HTML like so:

<my-component [filterSettings]="filterSettings$ | async"></my-component>

However, it's within an *ngIf statement which means it only gets evaluated after the search box opens. My assumption is that the async pipe subscribes after all actions are completed, and without new events, it does not receive a value. But why does it work with store.let? Is that a different type of observable always returning a value?

The main question: What mistake am I making, as I feel like something is still missing... And as a bonus question: Is this approach suitable for creating shadow copies of data that can be cancelled or submitted?

Answer №1

Instead of using a regular rxjs/Subject, consider implementing rxjs/BehaviorSubject. This way, the latest item received will be automatically passed on to new subscribers.

this.filterChanges = {};
this.filterChanges$ = new BehaviorSubject(this.filterChanges);

There is no need to call next() afterwards, as the value is provided in the constructor. After this change, Observable.combineLatest() should function correctly.

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

Disabling the background shadow effect in Angular Material's Accordion

I successfully disabled the background shadow on the Angular Material Accordion in this demonstration by incorporating the following CSS rule: .mat-expansion-panel:not([class*='mat-elevation-z']) { box-shadow: none !important; /* box-shadow: ...

ng-deep is causing changes in sibling components

Facing a challenge with Angular Material Design as I discovered the need to utilize ng-deep to customize the styling of an accordion. The issue is that when I use this method, it affects another accordion in a different section which is undesirable. Is th ...

The error message "this.startLoginAnimatioon is not defined as a function" popped up

I've been developing a login system using TypeScript but I keep encountering an error that I can't figure out. Here's the issue in detail: The problem arises when the this.startLoginAnimation() function is called within the attemptLog ...

Is Aurelia-Fetch reliant on whatwg-fetch as a dependency in its codebase?

I am currently in the process of updating my Aurelia project from a beta version to the March version. One of the issues I encountered is: Cannot locate name 'Request'. Searching online led me to this problem on GitHub: https://github.com/au ...

Iterating through a for loop in Angular2 to send multiple GET requests to a Django backend

Currently, I'm facing a challenge with performing multiple GET requests using Angular2 within a Django/Python environment. After successfully making an API request and retrieving a list of users to determine the current user's ID, I utilize a .f ...

"Exploring the process of setting up a custom environment for ng serve in Angular

According to the angular 6 readme: ## Development server Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. Prior to version 6, I used to run this command for m ...

Radio buttons may not appear initially upon loading the first page

Can anyone explain why the radio buttons are not visible when the page first loads? I am using Angular Material's mat-radio-buttons. Click here for the code ...

Eliminate the underscore from mat-select in (@angular/material 15.0.3)

Is there a way to remove the underline from mat-select? <mat-form-field style="margin: 2em 2em 2em 2em" appearance="fill" > <mat-label>Choose an option</mat-label> <mat-select> <mat-option value=& ...

Validation Form Controls

Here is a piece of code that works for me: this.BridgeForm = this.formBuilder.group({ gateway: ["", [Validators.required, Validators.pattern(this.ipRegex)]], }); However, I would like to provide more detail about the properties: this.BridgeF ...

Trigger the Material UI DatePicker to open upon clicking the input field

I have a component that is not receiving the onClick event. I understand that I need to pass a prop with open as a boolean value, but I'm struggling to find a way to trigger it when clicking on MuiDatePicker. Here is an image to show where I want to ...

Incorporating real-time checked checkbox values into a running list

When displaying a list of preferences as checkboxes, I encountered an issue with the binding part. I am trying to capture the IDs of the checkboxes that are checked. Here is my attempt, which unfortunately does not work: <div class="checkbox" *ngFor="l ...

Tips for troubleshooting the error "Cannot locate module mp3 file or its associated type declarations"

https://i.sstatic.net/q4x3m.png Seeking guidance on resolving the issue with finding module './audio/audio1.mp3' or its type declarations. I have already attempted using require('./audio/audio1.mp3'), but continue to encounter an error ...

Can we specify the type of a destructured prop when passing it as an argument?

I have implemented Material UI's FixedSizeList which requires rendering rows in the renderRow function and passing it as a child to the component. The renderRow function accepts (index, style, data, scrolling) as arguments from the FixedSizeList comp ...

Creating a responsive class getter with Vue.js 3 using the Composition API: a guide

How can I set up a class instance property to reactively display an error message when authentication fails? UserModel.ts export class User { private error: string; set errorMessage(errorMessage: string) { this.error = errorMessage; } get err ...

What is the best way to interpret the property 'subscribe' of an undefined object?

After cloning a MEAN stack application from GitHub, I made minor modifications by changing all instances of the word 'employee' to 'sensor'. The build was successful without any issues. However, upon launching localhost:4200, I encounte ...

Guide on creating a similar encryption function in Node JS that is equivalent to the one written in Java

In Java, there is a function used for encryption. public static String encryptionFunction(String fieldValue, String pemFileLocation) { try { // Read key from file String strKeyPEM = ""; BufferedReader br = new Buffer ...

An Unexpected ER_BAD_FIELD_ERROR in Loopback 4

I encountered an unusual error: Unhandled error in GET /managers: 500 Error: ER_BAD_FIELD_ERROR: Unknown column 'role_id' in 'field list' at Query.Sequence._packetToError (/Users/xxxx/node_modules/mysql/lib/protocol/se ...

Angular2 Navigation Menu

I have a side bar and I want its children to appear when the user clicks on the parent. For example, clicking on LinkTest should display its corresponding content as block. You can check out the Angular and Typescript code snippet at this link: http://jsfi ...

What is the best way to loop through an array that contains a custom data type

When I declared the type: export interface Type{ id: number; name: string; } I attempted to iterate over an array of this type: for(var t of types) // types = Type[] { console.log(t.id); } However, I encountered the following error message: ...

The information retrieved from the API is not appearing as expected within the Angular 9 ABP framework

I am facing an issue with populating data in my select control, which is located in the header child component. The data comes from an API, but for some reason, it is not displaying correctly. https://i.stack.imgur.com/6JMzn.png. ngOnInit() { thi ...