How can I effectively assign model data to a service property in an AngularJS controller?

I have established a service to facilitate the sharing of data/state across multiple controllers. One of the controllers updates certain properties within the service using scope data through a save function. The updated data is then accessed by other controllers by assigning a scope value to the service. However, I have encountered an issue wherein the behavior varies depending on whether the data assigned from the first controller to the service is a primitive value or an object. If it's a primitive value, the service's property only updates upon execution of the save function. On the other hand, if it's an object, the service continues to update as the model data changes. I am seeking to implement a "save" functionality and would like to understand why objects are immediately updated and how to properly handle object updates through the save function.

I am trying to comprehend the differences in behavior between primitives and objects, along with why objects update instantaneously. Additionally, I am exploring the best approach to implementing the save function with objects. While I am aware of utilizing events such as broadcasting an event on $rootScope and listening for it in the second controller to assign the service property to a scope variable, I prefer the simplicity of directly assigning the service to the scope in the second controller and would like to explore this method further if feasible.

Below is a simplified example:

var myApp = angular.module('myApp', []);

myApp.service('myService', function () {
    this.text = '';
    this.objText = {};

    this.setText = function (text) {
        this.text = text;
    };

    this.setObjText = function (obj) {
        this.objText = obj;
    };
});

myApp.controller('InputCtrl', ['$scope', 'myService', function ($scope, myService) {
    $scope.textObj = {};
    $scope.saveText = function (text) {
        myService.setText(text);
    }
    $scope.saveObj = function (obj) {
        myService.setObjText(obj);
    }
}]);

myApp.controller('OutputCtrl', ['$scope', 'myService', function ($scope, myService) {
    $scope.myService = myService;
}]);

In the view (partial):

<div ng-controller="OutputCtrl">
    <strong>Text:</strong> {{ myService.text }}<br>
    <strong>Obj Text:</strong> {{ myService.objText }}
</div>

For a complete demonstration, visit: http://jsfiddle.net/anpsince83/uRH93/2/

Answer №1

Angular has no role in this scenario. It's all about JavaScript at its core.

Reviewing the HTML of your fiddle (numbers indicated for reference):

(1)<input type="text" ng-model="text1">
(2)<button ng-click="saveText(text1)">Save Text</button>
   ...
(3)<input type="text" ng-model="textObj.text1">
(4)<input type="text" ng-model="textObj.text2">
(5)<button ng-click="saveObj(textObj)">Save Object Text</button>

The 'string' instance (primitive):

At Line (1), you initialize a string variable named text1 within InputCtrl's scope, bound to the input field value. Any change in the input field instantly reflects in inScope.text1. Upon clicking the button at Line (2), the text variable in myService gets assigned with the exact value from inScope.text1. Since 'string' is a primitive type, it's passed by value – meaning that myService.text and inScope.text1 don't point to the same object. They just coincidentally hold the same value post calling the saveText() method. If inScope.text1 changes (e.g., user input in the field), myService.text remains unaffected. This behavior can be summarized as:

var a = 'value1';
var b = a;
// Current: a === 'value1', b === 'value1'

a = 'value2';
// Current: a === 'value2', b === 'value1'

The 'object' scenario (object):

Lines (3) and (4) establish two properties (text1, text2) inside an initially empty object referenced by textObj within inScope. Modification in each input field triggers a corresponding update in the associated property of the object linked to inScope.textObj. After clicking the button at Line (5), myService's object references the very object pooled under inScope.textObj. Note the term reference instead of value. Given that 'object' isn't primitive, it’s passed by reference - implying both myService.object and inScope.textObj direct towards the same entity following the execution of saveObj(). Adjusting input field values stated in Lines (2) and (3) alters the properties of the object tied to

inScope.textObj</code (also pointed by <code>myService.object
). Analogous to:

var a = { key: 'value1' };   // New obj created, say {obj1}
var b = a;                   // b points to {obj1} too
// Current: a.key === 'value1', b.key === 'value1'

a.key = 'value2';  
// Presently: a.key === 'value2', b.key === 'value2'

// In your code, no loss of reference happens between `myService.object` and `inScope.textObj`
a = { key: 'value3' };   // Fresh creation - {obj2}
                         // Yet b still targets {obj1}, not {obj2}.
// Presently: a.key === 'value3', b.key = 'value2'

Further insights on JS primitives vs objects

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

Guide to adjusting column width in an XLSX worksheet using Angular4

I am trying to convert HTML into an XLSX sheet in Angular using SheetJS. However, I am encountering an issue where the width of each column is limited to 256 only, and I need to increase it. I have attempted to use ws[!cols] of ColInfo, but I am strugglin ...

Changing a class and audio and storing it using browser's local storage

The challenge I am facing: I am currently working on a feature for my website that allows users to toggle the volume on/off and have that setting persist across different pages. Specifically, I want the user's volume preference to be saved when they n ...

Tips for incorporating child components when creating unit tests in Angular 2

While working on my component, I encountered an issue with the child component during unit testing. An error message is appearing stating that the child component is not defined. Any advice or solutions would be greatly appreciated. Thank you in advance. ...

Using the class method to handle jQuery events alters the context

Is it possible to access the class context from within a method being used as a jQuery event handler? The example below illustrates the scenario: class EventHandler { constructor() { this.msg = 'I am the event handler'; } ...

The functionality of the .toggle method is limited to only being effective 1.5

I'm having an issue with making an image popup using the .toggle function in javascript. It seems to work initially, but then only works partially after that. When I click on the image, it opens as expected. However, when I try to close it by clickin ...

Guide to creating fog animations in three.js

I'm attempting to adjust the fog density using tweening, but for some reason, it doesn't seem to be working. Here are my default settings: var camera, densityFog, colorFog2; colorFog2 = 0xfee2ed; densityFog ...

Prevent Float Filtering in AngularJS

As I work on creating a directive in AngularJs, I am facing an issue. The directive is supposed to receive a JSON object from the app controller and display its content accordingly. To better illustrate my problem, I have created a simple demo which can b ...

How can we efficiently loop through all the icons in React Material-UI?

I am looking to iterate over all the icons from @material-ui/icons in a React application. If I want to import a single icon, I can do so like this import IconNameIcon from '@material-ui/icons/IconName' and then use it in my component like th ...

How can I import tamplateData into my JavaScript files in Docpad?

Looking for a DocPad plugin that can preprocess JS files and utilize templateData variables and helpers to access configuration values. While experimenting with Hogan, I managed to retrieve the variables but encountered difficulty in invoking the helpers. ...

Upon attempting to send a POST request with PostgreSQL, the following error is displayed: "Invalid input syntax for type integer: '12 Pro'"

I encountered an error while attempting to send a POST request using PostgreSQL/Sequelize. Can anyone help me identify the issue in this code? async create(req, res, next) { try { let { name, price, brandId, typeId, info } = req.body; c ...

What is the reason behind Babel including this redundant line of code in my build?

While utilizing Babel 7 and Gulp 4 in conjunction, I have noticed that the subsequent line of code is repeated five times within my build: function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterato ...

Ionic (Angular) experiencing crashes due to numerous HTTP requests being made

My template contains a list of items <ion-list class="ion-text-center"> <div *ngIf="farms$ | async as farmData"> <ion-item (click)="selectFarm(farm)" *ngFor="let farm of farmData" detail=&quo ...

AngularJS Material's UI style for a selected item is sophisticated and visually appealing,

I have a user interface with multiple buttons and I am looking for a way to visually highlight the buttons that users tap on for a few seconds. Are there any existing directives or styles available for this purpose, or do I need to create my own solution ...

Activate/Deactivate toggle using Vue.js

new Vue({ el: '#app', data: { terms: false, fullname: false, mobile: false, area: false, city: false, }, computed: { isDisabled: function(){ return !this.terms && !this.fullname && !this.mob ...

Adjusting window size when page is resized

While browsing through SO, I stumbled upon this interesting piece of code: var w = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0], x = w.innerWidth || e.clientWidth || g.clientWidth, y = w. ...

Attempting to deploy my node.js application on Heroku resulted in an error message saying that the web process failed to bind to $PORT within 60 seconds of launch, causing the process to exit with status

I recently encountered an issue while attempting to deploy my node.js app on Heroku. The error message stated that the Web process failed to bind to $PORT within 60 seconds of launch, and the Process exited with status 137. I'm unsure of how to resolv ...

Assign the DatePicker Object to an HTML Element

I am currently using a SyncFusion date picker in my project and the implementation looks like this: var datepicker = null; $("#datepicker").hide(); $("#click").click(function(){ $("#datepicker").show(); datepicker = new ej.calendars.DatePi ...

When I attempt to use document.execCommand("copy"), the line break does not get applied

I am currently using the following code to create a string and copy it. However, when I paste it as output, the line break is not being applied. function copyToClipboardShipto() { var $temp = $("<input>"); $("body").append($ ...

Link AngularJS service array length property to the controller's scope through binding

I am attempting to connect the length of an array from another service to my controller's scope in the following manner: app.controller('TestCtrl', function ($scope, safePostService) { $scope.count = safePostService.queue.length; $ ...