Exploring Angular2 Guides: Understanding Hierarchical Dependency Injection with a Focus on Service Restoration

As I delved into the Angular2 documentation, a specific example caught my eye in the Hierarchical Dependency Injectors chapter. It introduced me to the Restore service, which enables save/cancel functionality for editing.

The code for this service is as follows:

export class RestoreService<T> {
   originalItem: T;
   currentItem: T;
 setItem (item: T) {
   this.originalItem = item;
   this.currentItem = this.clone(item);
 }
 getItem () :T {
   return this.currentItem;
 }
 restoreItem () :T {
   this.currentItem = this.originalItem;
   return this.getItem();
 }
 clone (item: T) :T {
   return JSON.parse(JSON.stringify(item));
 }
}

Excited by this discovery, I decided to try it out myself! Firstly, I initialized the values like this:

ngAfterContentInit(){
     this.metadata = {
      languages: this.selected_languages,
      countries: this.selected_countries,
      international: false
     }
 }
 set metadata(metadata: CvMetadata){
      this._restoreService.setItem(metadata);
 }
 get metadata(): CvMetadata{
    return this._restoreService.getItem();
 }

Next, I proceeded to change the values of the metadata properties using ngModel, such as

[(ngModel)]="metadata.languages[0]"

The question:
To my surprise, when I update the value of the metadata property with ngModel, only the currentItem changes while the originalItem remains unaffected. This left me puzzled as I initially expected ngModel to trigger the setter method for setting the metadata properties. However, the setter is invoked only once during the initial data setup. How does ngModel differentiate between changing the currentItem and not touching the originalItem? Is this some form of magic at play?

I know it's quite a specific query, but alas, you are the only ones I have to turn to for an explanation!

Thank you!

Answer №1

RestoreService has two main functions: setter and getter;

setItem (item: T) sets the originalItem, creates a clone, and saves it as the currentItem.

getItem() simply returns the currentItem (the cloned item).

The ngModel retrieves the item's metadata to access its languages property. It operates on the currentItem. When updating a property value, ngModel does not need to reset the entire metadata(), just the specific languages property inside metadata.

Check out this Plunker example for more clarification.

Another way to explain it:

this.metadata = {language:['english']}; // By setting metadata, you effectively set originalItem and create a clone in currentItem

this.metadata.languages = ['arabic'];  // Access metadata "currentItem," update its languages property without altering metadata itself

Note about the clone function: The clone function within RestoreService does not perform a practical object cloning due to its use of JSON parser. Refer to these links for more efficient ways of cloning objects: 122102, 728360

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

Using arrow functions in node.js

Can someone help me understand how arrow functions work? I know that arrow functions are typed like this () =>, but I'm curious about how the function that contains the arrow function knows how to call it. For example: app.listen(3000 , () => ...

Reactivity in Vue on dynamically generated HTML elements

Experimenting with Vue 2, I attempted to generate DOM elements in the mounted hook as shown below: <div id="app"> <div id="container"> <label for="static_name">Existing field</label> <input ...

Utilizing Laravel and Jquery UI for asynchronous communication with the server, passing data from a post request to

I recently constructed a basic Jquery UI slider: $("#sliderNumCh").slider({ range: "min", min: 0, max: 20, step: 1, value: 20, change : function(e, slider){ $('#sliderAppendNumCh'). ...

Requests from a Heroku Angular frontend to a Heroku Spring Boot backend result in a 403 error code being returned

I successfully deployed a basic CRUD Springboot backend on Heroku. When I deploy the frontend to my local environment, the REST calls work without any issues. Using curl from either my local machine or the Heroku frontend bash also results in successful ...

Having trouble retrieving accurate text information from a JavaScript link

I am encountering an issue with my code which consists of links with divs inside them. When I click on a link, it should display another div with data for "Case No" and "Type". However, the problem is that it only fetches the data from the first link click ...

ERROR: An issue occurred while attempting to resolve key-value pairs

Within my function, I am attempting to return a set of key-value pairs upon promise completion, but encountering difficulties. const getCartSummary = async(order) => { return new Promise(async(request, resolve) => { try { cons ...

Is there a way to transform a regular CommonJS declaration into an ECMAScript import when it is making multiple requires in a single line?

As a beginner in JavaScript, I am interested in converting this line into an import statement: var sass = require('gulp-sass')(require('sass')); I have successfully converted the other requires into imports but I'm struggling wit ...

Connection lost from JS client in Twilio's Programmable Chat

My React application utilizes the Twilio Programmable Chat library for chat functionality. The setup code typically appears as follows, enclosed within a try/catch block: this.accessManager = new AccessManager(twilioToken.token); const chatClientOptio ...

Issues arise with controlling access due to cache-control and canvas properties

I am attempting to utilize the browser canvas feature to manipulate images that are hosted on cloudfront. My goal is to configure cloudfront in a way that allows the browser to cache images with cache control set to max-age, while still enabling canvas edi ...

using the newquestion variable later in the function

In the Vue.js code snippet below, there is a variable named newQuestion that is passed to the function getAnswer like this: this.getAnswer(newQuestion). Further down in the methods section, particularly at this line getAnswer: _.debounce(, I would like to ...

Incorporating JavaScript and CSS files into a content page of a master page in ASP.NET: Steps to follow

I am facing an issue with adding javascript files and css to a content page of a master page in asp.net. I attempted to include a datetime picker on my ContentPage, but it only works on the masterpage. When I try to add the same code to my contentpage, i ...

Is it possible to pass a useState function to a component during its initialization?

Currently, I am utilizing the useState hook to effectively handle the rendering of components on the screen. My goal is to initialize it with a component while passing in the useState function to set the screen within the component. Below is my App.js fil ...

Identical Identifiers in jQuery Tab Elements

Currently, I am utilizing the jQuery Tabs library within a small application. Within this page, there are 5 tabs that load content using Ajax. However, an issue arises when a tab is loaded and remains in the browser's memory along with its HTML elemen ...

Compatibility problem arising from the versions of ember-precompile, ember.js, and handlebars.js

Having trouble reading the precompiled templates in my HTML due to compatibility issues between ember-precompile, ember.js, and handlebars.js. My code looks like this: Includes the following files. <script src="../js/libs/jquery-1.10.2.js"></sc ...

Executing a function within a VueJs 2 component immediately after it has finished loading

How can I retrieve data after a component has finished loading? When I initialize my Vue instance and load the component, the template loads correctly but the functions in the mounted lifecycle hook are not executed, causing the stats object to remain empt ...

The call stack reached its maximum size while attempting to send a post request in an Express application

'Error Occurred: RangeError: Maximum Call Stack Size Exceeded' When Making a Post Request in Node.js with Express and body-parser As a beginner in the world of node.js, my journey took a challenging turn while following along with video #30 from ...

Exploring Heroes in Angular 2: Retrieving Object Information by Clicking on <li> Items

Currently, I am delving into the documentation for an angular 4 project called "Tour of Heroes" which can be found at https://angular.io/docs/ts/latest/tutorial/toh-pt2.html. <li *ngFor="let hero of heroes" (click)="onSelect(hero)">{{hero.name}}< ...

The body parser is preventing the NODE from loading on localhost

var express = require('express'); var app = express(); var bodyParser = require('body-parser'); //ISSUE LINE **app.use(parser.json);** /////////////// var todos = []; var nextTodoItem = 1; app.use(bodyParser.json); ap ...

Validating Angular Forms using NgIf

Currently working on a form that includes a textbox for the user's first name. Implementing verifications. Using a basic form with a single error line, everything functions correctly: <div class="col-12 col-md-6"> <inpu ...

Accessing and modifying the HTML content of a specific <td> element within a specified <tr> row

Thank you for the assistance with my previous question - it was very helpful. However, I have encountered a new issue. I am able to automatically refresh my "Table" every 5 seconds with the following code: function GetStatus() { $.ajax({ url: ...