Angular 8: How does the non-observable type get affected when the original data it was derived from is modified?

Utilizing Angular 8 and Ngrx 8 (just for context), I have a state service that controls the state of my view model. Within this service, there is a property called viewModel$ which is a behavior subject. Initially, when the service fetches its data, the viewModel$.next() function is invoked with the new view model value, simultaneously setting another property named originalValue to that same view model value. This process works as expected.

However, my intention was for the original value to remain unchanged so that if the user decides to revert changes, I can easily discard the updated view model and revert back to the original value. Unfortunately, each time the view model is updated, the originalValue property also gets modified – despite not being an observable. I suspect it has something to do with closures, but I lack the expertise to pinpoint the issue.

My main question here is: why is this unexpected behavior happening and how can I rectify it? How can I achieve the desired functionality of preserving the old data to enable reverting changes, without having to retrieve the data from the store again? Despite this workaround being viable, I am intrigued by what is causing the problem in the first place. Additionally, other components of the “Project” require simultaneous reversion, and I prefer not to incur the added time and effort of converting state models to view models if possible.

Below is the relevant code snippet:

In the state service,

Properties:

public viewModel$: BehaviorSubject<ProjectCoreViewModel>;
public viewModelLoaded$: BehaviorSubject<boolean> = new BehaviorSubject(false);
public originalValue: ProjectCoreViewModel;
public isPristine$: BehaviorSubject<boolean> = new BehaviorSubject(true);
private isInitialized = false;

Initial selection of data (via facade for retrieval from store):

public selectData() {
this.facade.getProjectCore()
.subscribe(core => this.fromStoreStateModel(core));
}

Conversion from state model to view model, followed by calling the updateViewModel$ method:

fromStoreStateModel(projectCore: ProjectCore) {

if (projectCore) {
const viewModel: ProjectCoreViewModel = {
// Data assignment
};
this.updateViewModel$(viewModel);

}
}

updateViewModel$ method:

updateViewModel$(value: ProjectCoreViewModel) {

if (value) {

// ViewModel check and initialization logic

}
else {
this.setLoadedStatus(false);
}
}

setOriginalValue method:


// Original value assignment logic

This piece in my component updates the view model:

// View model update logic

Answer №1

Seems like it's not a closure, rather you are sharing the same object in two different places and any modifications made in one place will reflect in the other as well.

To resolve this issue, consider making a copy of the object when saving it to this.originalValue. You can achieve this by changing the following line:

this.originalValue = viewModel;

to:

this.originalValue = {...viewModel};

I hope this solution proves useful for you.

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

Tips for preserving hyperlinks while elegantly containing them within a designated space

Today, while experimenting with new angular features, I encountered an issue that is shown in the link below: https://i.sstatic.net/p4pNc.png The "tags" on the page are expanding beyond the boundaries of their parent container (the white div). They wrap, ...

Adding HTML elements to Material 2 Snack bar: A step-by-step guide

I am in need of displaying a spinner inside Material 2 Snack bar. Within our application, we utilize Snack bar to showcase loading, success, and error messages. For the loading message specifically, I would like to include a spinner as well. However, my a ...

Leverage classes from a CommonJS module within a Typescript environment

I am facing an issue with my npm package setup. Here is a snippet from one of the files: 'use strict' module.exports = class TModel { constructor (app) { this.app = app } static schema () { } } I am trying to incorporate this int ...

The Child Component encountered difficulties in connecting to the EventEmitter via the service

In the code snippet below, we have the Subscribing Component "pop-list.component.ts" : import { Component, OnInit } from '@angular/core'; import { ChildCommService } from '../child-comm.service'; @Component({ selector: 'app-pop- ...

Refreshing display with information received from web socket in Angular 5

On my page, I am receiving an array of data upon page load and displaying it using the *ngFor directive. Additionally, there is a connection established to a Web Socket to receive updated data, which in this case pertains to a timetable for boat trips. The ...

The latest version of fork-ts-checker-webpack-plugin, version 5, cannot be reached from @vue/cli-plugin-types

Currently, I am updating the build container in my project from node:10-alpine to node:14-alpine. However, when I run npm ci (after rebuilding package-lock.json), I encounter the following error: npm ERR! fork-ts-checker-webpack-plugin-v5 not accessible fr ...

Expressions without a call signature cannot be invoked

When using an adapter in the given example, I encountered a type error specifically on the last line of the getGloryOfAnimal method. Despite having clearly defined types, I am puzzled by this issue. interface ICheetah { pace: string; } interface ILio ...

Setting up Webpack to compile without reliance on external modules: A step-by-step guide

I am facing an issue with a third-party library that needs to be included in my TypeScript project. The library is added to the application through a CDN path in the HTML file, and it exports a window variable that is used in the code. Unfortunately, this ...

Challenge with Bootstrap 4 post-transfer to Angular rc5 from rc beta

I recently upgraded my angular application from Beta version to Angular rc5. However, I encountered errors when attempting to add any bootstrap control in a component. (index):48 Error: (SystemJS) No Directive annotation found on Dropdown(…)(anonymo ...

Filtering tables with checkboxes using Next.js and TypeScript

I've recently delved into Typescript and encountered a roadblock. While I successfully tackled the issue in JavaScript, transitioning to Typescript has left me feeling lost. My dilemma revolves around fetching data from an API and populating a table u ...

What is the best way to allow a C# Web API method to be accessed from any origin?

My C# Web API includes the following method: public JsonResult PlanItems(string sessionId) { Response.Headers.Add("Access-Control-Allow-Origin", "*"); DTDBDataService svc = new DTDBDataService(_db); VM.PlanItems = svc.GetPla ...

Ways to render an input field uneditable, yet permit certain keys to retain functionality

I have a single input box displaying a value that I want to be read-only, but still allowing the arrow keys, Home key, and End key to function properly. The input box contains multiple URLs separated by commas, and I need to be able to navigate between th ...

Numerous calls are made to the Ionic 3 component, causing the query to continuously run without stopping

I am working on a project where I need to retrieve unique dates from a table and then use each date as a parameter to query another table for records to display in an HTML format. To achieve this, I have implemented a component, but I am facing issues with ...

Setting a variable in Angular after a successful AJAX call

Working on a new small application and experimenting with Angular. Encountering an issue where I am making an AJAX GET request upon clicking a button. After receiving the response, I want to set a variable to hold the result, but for some reason the variab ...

JavaScript library experiencing import issues with Typescript custom type

Working on a Vue project with TypeScript, I encountered an issue when importing a custom type created for the vue-numeral-filter package. The error message received is as follows: ERROR in /Users/bmartins/Development/app-invest/src/main.ts(14,30): 14:30 ...

Sharing boolean values between Angular components is not working as expected

I'm working on a simple use case but seem to be missing something. In this scenario, I have two components: componentA and componentB. I am trying to pass a boolean value from componentB to componentA using an eventEmitter in order to show/hide a spe ...

What is the reason behind the TypeScript HttpClient attempting to interpret a plain text string as JSON data?

When utilizing Angular TypeScript, I have implemented the following approach to send a POST request. This request requires a string parameter and returns a string as the response. sendPostRequest(postData: string): Observable<string> { let header: ...

Angular's ExpressionChangedAfterItHasBeenCheckedError is a common issue that developers encounter

This message continues the discussion about a persistent issue I have been facing. Here is the link to the original thread on Stack Overflow: stackoverflow.com/questions/44596418/angular-throws-expressionchangedafterithasbeencheckederror-with-textarea Af ...

What is the best way to close ngx-simple-modal in angular7 when clicking outside of the modal component?

Can anyone help me with closing the modal in my angular7 app when the user clicks outside of the modal component? I have been using the ngx-simple-modal plugin, and I tried implementing the following code: this.SimpleModalService.addModal(LinkPopupCompone ...

Can anyone point me in the right direction to find the Angular 2 Material Design styles within the

I am currently exploring the inner workings of the @angular/material library that is installed through npm. Upon inspection, I have noticed that the only style file visible is _theming.scss, primarily responsible for styling colors according to the selec ...