What is the best way to efficiently input identical data into multiple controllers ($scope) using just one call in AngularJS?

I have a situation where I am using a factory to make a call in two controllers on the same page. However, I want to avoid making an AJAX call twice. I tried using $q.defer(), but it doesn't seem to be working!

Here is the code snippet:

(function () {
    'use strict';

    var app = angular.module('globalApp', []).config([
        '$interpolateProvider', '$httpProvider',
        function ($interpolateProvider, $httpProvider) {
            delete $httpProvider.defaults.headers.common['X-Requested-With'];
            $interpolateProvider.startSymbol('<%');
            $interpolateProvider.endSymbol('%>');
        }
    ]);

    // Index Store List
    app.controller('IndexController', ['$scope', '$storeList',
        function ($scope, $storeList) {
            $scope.stores = [];
            $storeList.getStoreList().then(function (stores) {
                $scope.stores = stores;
            });
        }]);

    // Footer Store List
    app.controller('StoreListController', [
        '$scope', '$storeList',
        function ($scope, $storeList) {
            $scope.stores = [];
            $storeList.getStoreList().then(function (stores) {
                $scope.stores = stores;
            });
        }
    ]);
    
    // Factory call list of stores
    app.factory('$storeList', function ($http, $q) {
        var stores = [];
        return {
            getStoreList: function () {
                if (stores.length > 0) {
                    var deferred = $q.defer();
                    deferred.resolve(stores);
                    return deferred.promise;
                }
                var uri = rootUrl + 'getStoreList';
                var responsePromise = $http.get(uri);
                return responsePromise.then(function (result) {
                    var data = result.data;
                    if (data.status) {
                        var stores = data.stores;
                        return stores;
                    }
                });
            }
        };
    });

}());
<body ng-app="globalApp">

  <section>
    <div ng-controller="IndexController">
       <nav>
        <a ng-repeat="store in stores" href="<%store.link%>"><%store.name%></a>
      </nav>
    </div>
  </section>
  <footer>
    <div>
        <ul ng-controller="StoreListController">
            <li ng-repeat="store in stores">
                <h3><a href="<%store.link%>"><%store.name%></a></h3>
                <p>
                    <%store.street%>, <%store.number%>
                    <%store.neighborhood%>, <%store.cityName%>
                    <a><%store.phone%></a>
                    <a><%store.email%></a>
                </p>
            </li>
        </ul>
    </div>
   </footer>
</body>

Answer №1

When both controllers load simultaneously and invoke the function, the stores will be empty resulting in a length of 0.

If you need to perform this action on page load, consider calling the function from a service and storing the results. Implement an observer pattern in the controllers to track changes in the set and update both controllers with the values of $scope.stores once the promise is fulfilled.

Answer №2

Here is my solution:

(function () {
    'use strict';

    // Custom configurations
    var app = angular.module('globalApp', []).config([
        '$interpolateProvider', '$httpProvider',
        function ($interpolateProvider, $httpProvider) {
            delete $httpProvider.defaults.headers.common['X-Requested-With'];
            $interpolateProvider.startSymbol('<%');
            $interpolateProvider.endSymbol('%>');
        }
    ]);

    // Controller for Index Store List
    app.controller('IndexController', [
        '$scope', '$storeList', 'StoreService',
        function ($scope, $storeList, StoreService) {
            $scope.stores = [];
            $storeList.getStoreList().then(function (stores) {
                $scope.stores = stores;
                StoreService.setStores(stores);
            });

        }]);
  
    // Controller for Footer Store List
    app.controller('StoreListController', [
        '$scope', 'StoreService',
        function ($scope, StoreService) {
            $scope.stores = [];
            $scope.$watch(function () {
                return StoreService.getStores();
            }, function (stores) {
                $scope.stores = stores;
            }, true);

        }
    ]);
  
    // Service to share variables between controllers
    app.service('StoreService', function () {
        var stores = [];
        return {
            setStores: function (_stores) {
                stores = _stores;
            },
            getStores: function () {
                return stores;
            }
        };
    });
  
    // Factory that makes AJAX call to fetch list of stores
    app.factory('$storeList', function ($http) {
        return {
            getStoreList: function () {
                var uri = rootUrl + 'getStoreList';
                var responsePromise = $http.get(uri);
                return responsePromise.then(function (result) {
                    var data = result.data;
                    if (data.status) {
                        return data.stores;
                    }
                    return [];
                });
            }
        };
    });
  
}());
<body ng-app="globalApp">

  <section>
    <div ng-controller="IndexController">
       <nav>
        <a ng-repeat="store in stores" href="<%store.link%>"><%store.name%></a>
      </nav>
    </div>
  </section>
  <footer>
    <div>
        <ul ng-controller="StoreListController">
            <li ng-repeat="store in stores">
                <h3><a href="<%store.link%>"><%store.name%></a></h3>
                <p>
                    <%store.street%>, <%store.number%>
                    <%store.neighborhood%>, <%store.cityName%>
                    <a><%store.phone%></a>
                    <a><%store.email%></a>
                </p>
            </li>
        </ul>
    </div>
   </footer>
</body>

Answer №3

It is not necessary to include defer here. Please eliminate the following section:

          //is a request needed?
            if (stores.length > 0) {
                var deferred = $q.defer();
                deferred.resolve(stores);
                return deferred.promise;
           }

Both your IndexController and StoreListController are loading the store list, resulting in 2 AJAX calls. Remove this section from either of the two controllers:

        $scope.stores = [];
        $storeList.getStoreList().then(function (stores) {
            $scope.stores = stores;
        });

UPDATE

Upon further reflection, it appears that you are using the storeList outside the scope of your StoreController. Therefore, please remove the .getStoreList() call from StoreController only.

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 SQL statement functions correctly in the MYSQL command line but encounters issues when executed within a NODE.JS application

When running the following SQL as the root user, everything works fine: sudo mysql -u root -p DROP DATABASE IF EXISTS bugtracker; CREATE DATABASE bugtracker; USE bugtracker; However, when executing the node.js code, an error is encountered: Error: There ...

jQuery: How can I add ajax content dynamically? Trigger?

Currently, I am developing the frontend of a web application that heavily relies on AJAX functionality, such as loading comments. All AJAX requests are being handled through jQuery functions. I am curious if there is a way for me to detect these insertion ...

The frequency of the geolocation watchPosition in Cordova exceeds the set options

In my ionic/angularjs application, I am utilizing the geolocation plugin from this link: https://github.com/apache/cordova-plugin-geolocation Following the documentation, I have set up the watch configuration as shown below: var watchOptions = { freq ...

Is there a way to utilize the passValue function twice within Javascript?

Is there a way to display the value of an input field in multiple spots throughout the code? Currently, my code only passes it once. How can I rewrite it to show up again later in the code? //HTML: <input type="text" name="amount" onchange="passValue ...

Issue in Classic ASP/VBScript: Inconsistently generates incorrect ID post insertion

I've been tasked with creating a web application for a fundraising event at work, where users can make donations through PayPal. Initially, I decided to repurpose an old Classic ASP/VBScript project from over a decade ago and use an Access database. A ...

In angular.js, repeating elements must be unique and duplicates are not permitted

My view controller includes this code snippet for fetching data from an API server: $scope.recent_news_posts = localStorageService.get('recent_news_posts') || []; $http({method: 'GET', url: 'http://myapi.com/posts'} ...

What is the method for dynamically creating an object in AngularJS by utilizing variables?

Creating Javascript Objects Dynamically Dynamic Object Creation in AngularJS Although I have the ability to create objects on the fly, I am facing challenges when trying to incorporate it into my own code. Here is a snippet of what I currently have: var ...

Can dynamic data be loaded on page load and children on click without storing children in the parent's state?

I have a dilemma with loading dynamic data on my fiddle. You can check it out here: https://jsfiddle.net/61qxn7av/2/ The issue is that each parent should have different children and these children need to append to the correct parent based on which checkb ...

Dialogue Inventory System

I am in the process of developing a conversation system that includes a page where users can view all of their conversations and select which one they want to reply to. The layout is structured as follows: You can view an image of the layout here. The co ...

Check out the page design for section one!

I have been attempting to create a link to a specific section on a one-page website. Sometimes it works oddly, but most of the time it gets stuck at the section I clicked on and then manual scrolling does not function properly. From what I've researc ...

Using a variable as an argument for a DOM function in JavaScript

I found this code snippet on a website and made some changes to it. However, the modified code below is not functioning as expected. My goal was to hide the div with the id "demo1", but for some reason, it's not working. What could be causing this is ...

Experiencing difficulty when attempting to save a zip file to the C drive

I came across this code snippet on SO and decided to use it for my project. The goal is to send a simple 1.5mb zip file and save it on my C drive by making a request through Postman with the binary option enabled, sending the zip file to localhost:3012. c ...

Javascript Mouse Events Not Functioning Properly with Three.JS Scene Components

Currently feeling quite perplexed (probably due to fatigue from working on this at an inopportune time). I'm in the midst of trying to configure my three.js application to trigger distinct functions based on different mouse events when the cursor hove ...

What are some ways to escape an ng-repeat loop?

Instructions for breaking out of a specific item in an ng-repeat loop <div ng-init="myarr=['abc','xyz','pqr','mno','rst']"> <div ng-repeat="item in myarr"> {{item}} ...

Is it possible to hide and reveal specific form elements based on the selection of a checkbox?

Having issues with the code provided below, it's not working as expected. Can you help me figure out what I might be missing? HTML: <input id="id_code_col" type="checkbox" name="code_col"></input> SCRIPT: $(document).ready(function(){ ...

Is it possible to have multiple POST requests for an ApiController?

The situation: Imagine a User class that consists of various groups of properties: password, address, preference, and roles. We require different Ajax requests to update (1) the user's password, (2) their profile, and (3) the roles they belong to. ...

Transforming date and timezone offset into an isoDate format using moment.js

When retrieving data from the API, I encounter Date, Time, and Offset values in separate columns. My goal is to obtain an ISO date while maintaining the original date and time values. const date = "2019-04-15" const time = "13:45" const ...

choose a value from a dropdown menu to reset other dropdowns to their default values

I am encountering an issue with my PHP form that consists of 7 dropdown lists. Whenever I select a value from one of the dropdown lists, I want the other 6 to reset to their default values if they were previously opened. I believe using JavaScript is neces ...

Avoiding the utilization of HTML forms

Is it acceptable to send form information using jQuery instead of creating an HTML form? By skipping the traditional HTML form and using $.ajax in jQuery, are there any security, performance, or semantic issues to be concerned about? Does this approach a ...

loading a dynamic grid using Ajax with jQuery

Setting up a jquery grid on a standard webpage gridPage.html involves incorporating HTML and JavaScript code as follows: $("#gridtable").jqGrid('setGridParam', { data: [ {'type': 'aType', ...