One interesting aspect of angular .service() is how its singletons allow for the sharing of data across controllers, despite each instance being instantiated as new

Check out the following vanilla JavaScript code snippet:

var newable = function() {
    this.name = 'First';
  this.setName = function(name) {
    this.name = name;
  }
  this.getName = function() {
    return this.name;
  }
}

var n = new newable();
var m = new newable();

n.setName('second');
console.log(n.getName()); //second
console.log(m.getName()); //First

How can angular services instantiated using 'new' act as singletons and share data across controllers? Is the use of 'new' here misleading in terms of creating singleton instances?

Answer №1

When it comes to services in Angular, they are instantiated using the new keyword but behave as singletons because the instance is only created once. Subsequent calls to inject dependencies will simply return the existing instance, allowing controllers to access the same data within that service. Despite the use of new, it may seem like a new instance is created each time, but in reality, it's only called once.

To illustrate this concept, I've put together a simplified example that mimics Angular syntax. This example aims to provide a better understanding of what happens behind the scenes when dealing with services and controllers.

// var module = angular.module('myApp'); // Commented this out as I'm mocking what Angular does

var module = {
    controller: function(name, arg){
        var fn = arg.splice(arg.length - 1, 1)[0]; // Split the array and retrieve the controller's constructor
        var deps = [];
        for(var i = 0; i <  arg.length; i ++){
            deps.push(this.service(arg[i])); // Retrieve or construct services
        }
        return fn.apply({}, deps); // Apply dependencies with a new object assigned as 'this'
    },
    controllers: {},
    service: function (name, fn){   // Simplified version of what module.service likely does to instantiate a singleton
        if(!fn) return this.services[name]; // Retrieve the service if it already exists
        if(this.services.hasOwnProperty(name)) {
            return this.services[name]; // Return the existing instance if available
        } else {
            this.services[name] =  new fn(); // Create a new instance if one doesn't exist
            return this.services[name];
        }
    },
    services: {}
};

var instances = 0;   // Global counter to track how many times the constructor is called despite using 'new'
function ServiceConstructor(){
    instances++;
    this.instanceId = instances;  // Assign a unique instance ID based on the global counter
}
// Manually create a couple of services
var a = module.service('myService', ServiceConstructor);
var b = module.service('myService', ServiceConstructor);

// Create mock controllers with injected services
var ctl = module.controller('testCtl', ['myService', function(myService){
    this.myService = myService;
   console.log(myService.instanceId);
    return this;
}]);

var ctl2 = module.controller('testCtl2', ['myService', function(myService){
    this.myService = myService;
    console.log(myService.instanceId);
    return this;
}]);

console.log(b);
console.log("Are a & b the same?", a === b);  // True
console.log("InstanceIds:", a.instanceId, b.instanceId); // 1 , 1
b.testProp = "Yep definitely the same";
console.log(a.testProp); // Yep definitely the same
console.log("Are all 4 service references the same?", (a === b) === (ctl.myService === ctl2.myService));

var c = new ServiceConstructor();  // Call the service's constructor manually for testing purposes
console.log("Are b & c the same?", b === c) // false - c was manually instantiated
console.log ("b & c instanceid's: ", b.instanceId, c.instanceId); // 1, 2
console.log("Total instances:", instances); // 2 total instances created

Answer №2

Per the Angular documentation:

Angular services are:

  • Created lazily – Angular only creates a service when it is needed by an application component.
  • Singletons – Every component that relies on a service receives a reference to the one instance produced by the service factory.

Hence, a service is initialized when the first application component requiring it is used, and subsequently, any other components dependent on that same service obtain a reference to the single instance generated by the service factory.

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

The ng-include feature seems to be malfunctioning

After building a basic web page using AngularJs, I ran into an issue when attempting to integrate header.htm into index.html - nothing was displaying in the browser. index.html <html> <script src="https://ajax.googleapis.com/ajax/libs/angul ...

Create a separate mongoose schema for every element in an array by utilizing ecmascript 6

After traversing an array, I create a new mongoose schema by adding two fields and then saving it. myArray.forEach(email => { const newUsers = new UserList({ email, uuid: uuidv4() }); newUsers.save().catch(err => console ...

Merging a VUE project and a .NET framework project to unleash their full potential

Currently, I am working on a project that involves using VUE for the client side and .net framework for the server side. However, these two components are hosted as separate projects, requiring me to open different ports during development. I am aware tha ...

Exploring the history and present state of Vue lifecycle hooks

Is there a way to access previous and current data in the updated lifecycle hook in Vue, similar to React? I want to be able to scroll a list of elements to the very bottom, but for this I need: The already rendered updated DOM (to calculate the scroll) ...

Updating a webpage using Ajax in Django

I've been diving into Django and am eager to implement ajax functionality. I've looked up some examples, but seem to be facing a problem. I want to display all posts by clicking on a link with the site's name. Here's my view: def archi ...

Transforming a JSONP request to automatically parse a text response into JSON

If I have the following request $.ajax({ type: "GET", dataType: "jsonp", jsonp: "callback", jsonpCallback: "my_callback", url: my_https_url, headers:{"Content-Type":"text/html; charset=utf-8"}, success: function(data) { ...

Steps for redirecting to an external URL with response data following an HTTP POST request:

this.http.post<any>('https://api.mysite.com/sources', [..body], [...header]) .subscribe(async res => { const someData = res.data; const url = res.url; window.location.href = url }) After redirecting to the specified UR ...

Adding a disabled internal Style node to the HTML5 DOM: A simple guide

According to this, the style tag can be turned off using the disabled attribute. I attempted the following: <head> <style>body { color: black; }</style> <style disabled>body {color: red; }</style> </head> <bo ...

"Reposition all elements contained within a div that have a specific class

I'm completely new to Javascript and I've been trying to move all elements with a specific class inside a particular div. After doing some research, I found a solution that worked using IDs. However, when I tried to adapt it to work with classNam ...

Ensure the validation of multiple form fields in a single function

I've implemented code to validate a form field as you input values, changing the border color to red if invalid or green if valid: function FormValidation(){ var fn=document.getElementById("firstName").value; if(fn == ""){ document.ge ...

Receive Real-Time Notifications -> Update Title Using an Array Retrieved from a JSON File

I've been working on updating a live chart every 5 seconds with new data from the database. While I could easily update the information, I encountered a problem when trying to set a path within the chart options for tooltips callbacks afterTitle. Spec ...

Sometimes the AngularJS scope is refreshed only intermittently

I am encountering an issue with a list of cards retrieved from an API and displayed in a table using ng-repeat. The problem arises when I attempt to delete a card - sometimes it remains in the view, while other times it disappears as expected after confirm ...

Utilizing AngularJS: Incorporating a Service into a Directive

I am facing an issue with injecting a service into a directive, even though it works fine with my controller. The documentation suggests that it should be straightforward. Service: priceGraphServices = angular.module('priceGraphServices', [&apo ...

Understanding how to utilize and manipulate this JSON data using JavaScript

In my code, there is a variable that contains the following data: { "Rows": [ { "New":1, "CachedNumberType":0, "Date":1327479615921, "Type":2, "Number":"123456", "Duration ...

Rendering elements in React using a unique key for each item

Is there a difference between rendering an array of messages with fixed keys versus generating random keys each time? When looking at this code: render() { return this.props.messages.map((message) => ( <Message key={generateRa ...

Is it possible to trigger an event just once?

Is there a way to ensure an event only fires once? I recently discovered that using .one seems to do the trick. ...

I am struggling to send an email using PHP mailer with POST data

i'm facing challenges with integrating phpmailer and ajax. As a beginner in ajax, I still have some gaps in understanding the concept. When I directly run my php mailer script on a page with preset values, I can successfully send out an email. However ...

Please indicate the generator title (for example, nx generate @nrwl/workspace:library) specifically for Angular

Currently, I am expanding my knowledge in web development. While working with Angular, I encountered an issue when trying to create a new component. The error message reads "Specify the generator name (e.g., nx generate @nrwl/workspace:library)" after exec ...

Tab knockout binding

I have a section in my HTML with 2 tabs. The default tab is working properly, but when I attempt to switch to the other tab, I encounter an error. Can anyone provide assistance in determining why this error occurs? Here is the HTML code: <ul class="na ...

retrieving nested data utilizing Node.js / JavaScript

let data = [ { "testingNewValue": { "en-US": "hello" } }, { "testingNewValue": { "hi-IN": "hello " } }, { "testingNewValue": { "us": "dummy" } }, ...