Best practices for sharing data between controllers in an Angular application

It appears that this topic has been discussed before, but...

While service or events can be used for this purpose, there is conflicting information online about the frequency of using events.

Creating a separate service may not be the ideal solution either. How can data changes be monitored? How should notifications be handled? More events?

And what about the performance implications of each approach?

So, what is truly the optimal and perhaps the best method for sharing data between controllers in an Angular application? Is it even advisable to do so? Could it indicate underlying architectural or conceptual issues within our application?

Please provide guidance and advice

Thank you in advance

UPDATE

This question arises frequently, as there are scenarios where data sharing becomes necessary. I am curious if this aligns with Angular's principles.

Answer №1

Scope inheritance can be one approach to sharing data:

angular.module('app', [])
.run(['$rootScope', function($rootScope){
  $rootScope.sharedObj = {search:''};
}])
.controller('navCtr',['$scope',function($scope){
}])
.controller('routeCtr',['$scope',function($scope){
  $scope.$watch("sharedObj.search",function(d){
    $scope.data = d ? 'Searched data is ' + d : '';
  });
}]);
.main div{
  display:inline-block;
  border:1px solid black;
  height:100px;
  vertical-align: top;
}

.navigation{
  width: 20%
}
.navigation input{
  max-width: 70%;
}

.page {
  width: 75%
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" class="main">
  <div ng-controller="navCtr" class="navigation">
    search: <br/>
    <input ng-model="sharedObj.search"/>
  </div>
  <div ng-controller="routeCtr" class="page">
    {{data}}
  </div>
</div>

Alternatively, using a shared service can also achieve the same result:

angular.module('app', [])
.factory('srcObject',[function(){
  return {
    value: ''
  }
}])
.controller('navCtr',['$scope', 'srcObject', function($scope, srcObject){
  $scope.search = srcObject;
}])
.controller('routeCtr',['$scope', 'srcObject', function($scope, srcObject){
  $scope.$watch(function(){return srcObject.value},function(d){
    $scope.data = d ? 'Searched data is ' + d : '';
  });
}]);
.main div{
  display:inline-block;
  border:1px solid black;
  height:100px;
  vertical-align: top;
}

.navigation{
  width: 20%
}
.navigation input{
  max-width: 70%;
}

.page {
  width: 75%
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="app" class="main">
  <div ng-controller="navCtr" class="navigation">
    search: <br/>
    <input ng-model="search.value"/>
  </div>
  <div ng-controller="routeCtr" class="page">
    {{data}}
  </div>
</div>

Answer №2

One efficient way to bind the context of the controller directly to the service is by avoiding excessive use of $scope, minimizing property definitions in directive's isolate scopes, and eliminating the need for interaction with $rootScope. By leveraging this approach, you can ensure that everything requiring binding is linked to the internal API of your global service.

This strategy proves valuable for applications necessitating extensive data sharing and awareness among numerous components. It was successfully implemented in a video player project where various application parts needed to exchange information and access each other’s status, such as the number of video players on-screen, their current time, duration, and source.

Nevertheless, this pattern may not be ideal for constructing fully reusable components since it mandates reliance on a specific service within the directive. Nonetheless, consolidating all necessary properties for your application components into a single value component enables convenient definition of your internal API.

Regarding performance implications of sharing substantial objects via dirty checking, potential burdens should be considered.

directive

function() {
    return {
        //if you want the service to hold all the data the directive needs
        //you don't need to define any properties here
        scope: {},
        controller: "SomeCtrl"
    };
}

directive's controller

angular
    .module("app")
    .controller("SomeCtrl", ["globalService", function(globalService) {
        var vm = this;
        vm.globalService = globalService;
    }]);

html

<div>{{vm.globalService.someProperty}}</div>

in some deeply nested template url

<!-- another tradeoff is the long naming that can result -->

<div 
    ng-click="panel.state = !panel.state;"
    ng-repeat="panel in vm.globalService.dashboard.sidebar.panelConfig">{{panel.display}}</div>

constants

angular
    .module("app")
    .value("internalAPI", {
        someInitializedThing: true,
        someConfig: [
            { state: true, display: "foobar" },
            { state: false, display: "starts off false" }
        ],
        dashboard: {
            sidebar: {
                panelConfig: [
                    { display: "one panel", state: true },
                    { display: "special panel", state: false }
                ]
            }
        }  
    });

let your service register the API you've defined

angular
    .module("app")
    .service("globalService", ["internalAPI", function(API) {
        var tmp = {};
        for (var p in API)
            tmp[p] = API[p];
        return tmp;
    }])

    //now someplace else, globalService.someNavBar = true

Answer №3

If you're interested in sharing data between controllers, I recommend checking out my post on the topic:

Don't forget to take a look at the JSFiddle example linked at the end of the blog post for some hands-on practice!

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

Enforce the splicing of the ng-repeat array with the utilization of track by

Our app incorporates a task list that can potentially grow to a substantial size. The main task list is accompanied by a sidebar, where selected tasks can be edited using a different controller (TasksSidebarCtrl instead of TasksCtrl which handles the list ...

Display or conceal fields depending on custom object specifications

I am attempting to centralize my show/hide functionality for fields in one object (like vm.foo) that contains key-value pairs. For example, I could add another pair like 1502: true to hide a field with the key 1502. Is there a way to pass variables from t ...

Experiencing SyntaxError when utilizing rewire and mocha for Node.js testing. Unexpected token encountered

Trying to test a function exported from a nodejs file, I am utilizing q to manage promises. The function returns a promise that is either resolved or rejected internally through a callback. Within this callback, another function from a different location i ...

What is the best way to show only the weekdays on the x-axis?

My goal is to create a scatter-linked graph using D3.js, showcasing the people count for various shifts on different dates in January 2020. Here is the code snippet I am working with: <!DOCTYPE html> <html lang="en" > <head> & ...

Incorporating external JavaScript files into a React Element

I am currently revamping my Portfolio Site to incorporate modals into one of the pages as part of the transition to a Single Page Application (SPA). The JavaScript code for these modals is stored in a "main.js" file, and the necessary tags are included in ...

Adjust the color of input labels using jQuery validate

I have a form where I want to change the class of the input labels when a specific field fails validation. My goal is to add the 'error' class to the spans that are directly above any invalid form elements. Here is an example of my HTML structur ...

Which approach is more impactful: consistently sending an ajax request or breaking down the result within a function?

My JSON data consists of news entries with titles, text, and dates. Here is an example: { "news": [ {"title": "some title #1","text": "text","date": "27.12.15 23:45"}, {"title": "some title #2","text": "text","date": "26.12.15 22:35"}, ... ...

Update the appearance of an element in real-time using VUEJS

I am trying to use VueJS to dynamically change the position of a div. In the data function, I have a variable called x that I want to assign to the top property. However, the code I wrote doesn't seem to be working. Here is what it looks like: <tem ...

The functionality of using an Ajax call to invoke a php function on the same page is not functioning correctly

I am facing an issue where Ajax is not working in the same PHP file as the PHP function I want to call. My goal is to have a button that, when pressed, will trigger the function without reloading the page. I have placed my Ajax script at the bottom and the ...

Error occurred while attempting to upload a file using multipart form data: TypeError message displayed - Unable to access properties of undefined (specifically '0')

I am encountering an issue while trying to send multipart/form-data using axios from the frontend. The same post request works fine in Postman/Insomnia but fails when executed from the frontend. The backend shows the following error: node:events:505 ...

What is the best way to generate a new DIV every time a button is clicked?

I am attempting to make a square DIV that is red and measures 100x100 pixels. Each time a button is clicked, I want the square to be created. However, the code I have written is not functioning properly: <html> <title> Create New Div ...

PHP cannot be utilized within the script tag

I'm currently using JavaScript to display an error message If a user inputs incorrect information and I add the following code: <?php $_POST["usernamereg"] ?> = usernamereg; the alert function stops working. However, if I remove this code, t ...

Stop ajax loading animation for a specific scenario

I usually have a global ajax load animation that runs during every ajax call. However, there are certain cases where I need to disable this effect. How can I achieve that? This is the code for the global animation : $(document).ajaxStart(function(){ $ ...

What is the process for exporting an SVG file from a web page?

<svg class="paint" version="1.1" xmlns="http://www.w3.org/2000/svg"> <rect class="svgobject" x="458" y="165.28750610351562" width="142" height="56" fill="black" stroke="black" id="154" transform="translate(0,0)"> </rect> </svg> ...

Troubleshooting jQuery masonry problem related to initial display and height settings

Within a div, there is a masonry container with the inline style property display:none. With several divs on the page, clicking their respective buttons during load causes them to switch like a slideshow. This disrupts masonry's ability to calculate t ...

Unable to fetch data using getJSON method

objecten.js var objectData = [ { image: 'gallery/objecten/bear.jpg', thumb: 'gallery/objecten/bear.jpg', title: 'my first image', description: 'Lorem ipsum caption&apos ...

Enhance the Facebook Login popup with personalized settings

When a user clicks, a popup is triggered: FB.login(function () { // My CallBack }, { scope: 'email,user_birthday,user_location,user_hometown' }); This generates a Facebook login link with multiple parameters. I desire to inc ...

transferring data from JavaScript on the client side to Express on the server side

Using JavaScript, I have created the HTML DOM that you see in the code below. Now, my goal is to send the value of an input created in JavaScript to the server side. The server is built with node.js and express framework. Once the value is sent to the serv ...

Generating a unique event triggered by element class change

Is it possible to create custom JavaScript events that are triggered when elements receive a specific class? I am trying to monitor all elements within a table and perform certain actions once a particular class is added to them. Can this be done, and if ...

What is the recommended sequence for using decorators in NestJS: @Body(), @Params(), @Req(), @Res()?

How can I properly access the res object to send httpOnly cookies and validate the body with DTO? I keep running into issues every time I attempt it. What is the correct order for these parameters? ...