Collaborative service involves objects passing through reference

I am encountering an issue with a shared service in angular. Upon application startup, the init function is triggered, fetching and returning data that is vital across the entire application.

Components have the ability to inject this service and retrieve the data; however, the data can be altered within the component as well. In my current setup, every modification made to the object within my component reflects on the object returned by the shared service.

@Injectable()
export class SharedDataService {
   private _object1: SomeType[];
   private _object2: SomeType[];
   private _object3: SomeType[];

   constructor(private _http: HttpClient, @Inject('BASE_URL') private _baseUrl: string) {}

   public init() {
       this._http.get<IInitModel>(this._baseUrl + 'init').subscribe(
            (r: IInitModel) => {
                this._object1 = r.object1;
                this._object2 = r.object2;
                this._object3 = r.object3;
            }
   }

   public getObject1(){
       return this._object1;
   }

   public getObject2(){
       return this._object2;
   }

   public getObject3(){
       return this._object3;
   }

The init() function is executed during app startup to acquire essential data for the application. Within my components, I access this data like so:

export class SomeComponent {
    public object1: SomeType[];

    constructor(private _sharedDataService: SharedDataService) {}

    ngOnInit() {
       this.object1 = this._sharedDataService.getObject1();
    }
}

If I make changes to the object in the ngOnInit method of my component

this.object1.push({ prop1: 1, prop2: "SomeValue" })

The private member's value in the shared service also gets altered.

console.log(this._object1) // Output from shared service: [{ prop1: 1, prop2: "SomeValue"}]
console.log(this.object1) // Output from component injecting the service: [{ prop1: 1, prop2: "SomeValue"}]

Is this behavior expected? Are objects passed by reference when returned as implemented in my service?

Could someone suggest a more efficient approach to address this scenario?

Answer №1

When working with JavaScript, it's important to understand that objects and arrays are set as references.

For instance:

const obj1 = { name: 'Surjeet' }; // You have obj1 with a name property
const obj2 = obj1; // by assigning, you're setting the reference of obj1 to obj2
obj2.name = 'Yuvi'; // if you change obj2.name, it will also reflect on obj1.name
console.log(obj1.name) // It will display Yuvi
console.log(obj1.name) // It will still show Yuvi

Therefore, in such scenarios, it's essential to create a deep copy of your object. This can be done using the

spread operator or tools like lodash
.

Using Spread Operator

const arr = [1,2,3,4]
const copiedArr = [...arr];

Using Lodash

const arr = [1,2,3,4]
const copiedArr = _.cloneDeep(arr);

In your specific case, modify it as shown below

export class SomeComponent {
    public object1: SomeType[];
    constructor(private _sharedDataService: SharedDataService) {}
    ngOnInit() {
         this.object1 = _.cloneDeep(this._sharedDataService.getObject1());

         //OR

         //this.object1 = [...this._sharedDataService.getObject1()]; 
    }
}

Answer №2

If you want to duplicate your object, consider using lodash library.

https://lodash.com/docs/4.17.15#cloneDeep

@Injectable()
export class SharedDataService {
   private _object1: SomeType[];
   private _object2: SomeType[];
   private _object3: SomeType[];
   constructor(private _http: HttpClient, @Inject('BASE_URL') private _baseUrl: string) {}

   public init() {
       this._http.get<IInitModel>(this._baseUrl + 'init').subscribe(
            (r: IInitModel) => {
                this._object1 = r.object1;
                this._object2 = r.object2;
                this._object3 = r.object3;
            }
   }

   public getObject1(){
       return _.cloneDeep(this._object1);
   }

   public getObject2(){
       return _.cloneDeep(this._object1);
   }

   public getObject3(){
       return _.cloneDeep(this._object1);
   }
}

Another option is

Object.assign(target, ...sources)
. This method allows you to copy enumerable own properties from multiple source objects to a target object and returns the target object.

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

Trigger a click event on a third-party webpage that is embedded within an Angular application

In the process of developing my angular application, I found a need to incorporate a graph visualization tool. To achieve this, I utilized the HTML <embed> tag and successfully integrated the graph into my application. Now, my objective is to enable ...

The seamless union of Vuestic with Typescript

Seeking advice on integrating Typescript into a Vuestic project as a newcomer to Vue and Vuestic. How can I achieve this successfully? Successfully set up a new project using Vuestic CLI with the following commands: vuestic testproj npm install & ...

Converting text data into JSON format using JavaScript

When working with my application, I am loading text data from a text file: The contents of this txt file are as follows: console.log(myData): ### Comment 1 ## Comment two dataone=1 datatwo=2 ## Comment N dataThree=3 I am looking to convert this data to ...

Trouble with Angular ngFor Grouped Data Display

I'm trying to develop an accordion layout that organizes sessions into different levels. I've created a custom pipe which successfully groups the data with keys and values. However, when I try to display this information in the UI, only blank va ...

Challenges with slow performance in Ionic application when handling extensive amounts of data

We're facing performance issues with our ionic angular contact management app. The app experiences severe slowdown as the number of contacts increases, affecting taps, scrolls, and overall responsiveness. Despite utilizing offline storage to store da ...

Guide on compiling SCSS to CSS when running npm start

When running my application with npm start, I'm unable to compile scss files to css live. Is there a way to achieve live reload for sass to css similar to how ts are compiled to js by the tsc:w utility? Currently, I have to stop the build, then run gu ...

Divide Angular ngFor into separate divs

Here is an example of my current array: [a, b, c, d, e, f, g, h, i] I am aiming to iterate through it using ngFor and split it into groups of 3 elements. The desired output should look like this: <div class="wrapper"> <div class="main"> ...

Issue with decompressing the identical data using zlib (Z_BUF_ERROR)

Below is the Python code snippet I am working with: import zlib raw = bytes.fromhex("789C34C9410AC2301005D0BBFC752289A88BB94A53CAD8061B48D3329D2A1A7277DDB87BF02A14548E9C0DF63FD60DE49DC104AA98238BDE23EB908A467972065DFCF9FAFB4185C708EAD0053C58E38BDF769 ...

The expiration date is not considered in JWT authentication using passport-jwt

I have been working on implementing an authentication system using JWT token in Express, utilizing passport-jwt and jsonwebtoken. Everything is functioning correctly at the moment, however, I am facing an issue where the token remains valid even after its ...

Adjusting image dynamically based on conditions

I need to dynamically display images on my HTML based on specific conditions using TypeScript. In my TypeScript file: styleArray = ["Solitary", "Visual","Auditory","Logical","Physical","Social","Verbal",]; constructor(){ for (var i = 0; this.sty ...

Tips for resolving relative child routes in Angular

Routing Configuration const routes: Routes = [ { path: '', loadChildren: './home/home.module#HomeModule' }, { path: 'admin', loadChildren: './admin/admin.module#AdminModule' } ]; Nested Home Routing const ro ...

Steps for generating a multer file using a link to an image

My current challenge involves downloading an image from a public URL, converting it into a multer file format, and then uploading it using an existing API. So far, I've experimented with axios using responseType: "blob" and responseType: "arraybuffer" ...

The tag 'ngRedux' is not recognized as a property on the 'AppModule' type

After working tirelessly to integrate redux into angular6, the application is functioning smoothly. However, an error is being thrown in the node cli - 'Property 'ngRedux' does not exist on type 'AppModule'. Whenever I include N ...

Forcing locale in Angular 2: A step-by-step guide

I recently developed a compact application with Angular2 and incorporated the currency pipe. I noticed that the currency is automatically formatted based on my browser's language. Is there a way for me to customize or override this default behavior? ...

Appending an item to an array in TypeScript

I'm feeling lost. I'm attempting to insert new objects into an array in TypeScript, but I encountered an error. My interface includes a function, and I'm puzzled. Can anyone offer guidance? interface Videos{ title: string; descriptio ...

Repeating the same algorithms in both the back and front ends while applying Domain Driven Design

Within my class, I have some backend calculations: public class MyDomainClass{ private Double amount; private Double total; public Double getPercentage(){ /*business logic*/ } } I am using Angular 2+ for my frontend and I am looki ...

Is it possible to verify the absence of an error icon when valid data is provided in Angular testing?

Currently, I am utilizing the Selenium webdriver for Angular Automated testing. My scenario involves displaying a tooltip icon with an error message if the data provided is invalid. If the data is valid, the tooltip icon does not show up. Although, I have ...

TypeScript - ESBuild - Encountered an unexpected '<' token

When compiling TypeScript files for a React app with esbuild, everything goes smoothly. However, upon checking the browser console, an error pops up: An unexpected token '<' is causing errors after the return statement // components/editor/ ...

When attempting to import a react component written with TypeScript to npm, receiving an 'undefined' error

I recently encountered an issue when trying to publish my custom React component developed with TypeScript on npm. Although the publishing process was successful, I faced an error upon importing the npm package into a new React project: Error: Element ty ...

Getting event properties in a React component using the rest operator: A comprehensive guide

Can someone please assist me? I am new to TypeScript and struggling with how to use event props in my component. I have defined two props and need all my events as rest props. I encountered an error when trying to use my component with onClick event. The ...