Creating an automated sequence of $http requests to sequentially retrieve JSON files with numbered filenames in Angular 1.2

I have a series of JSON files (page1.json, page2.json, etc.) that store the layout details for our website pages.

Initially, I would load each page's data as needed and everything was functioning smoothly. However, it is now necessary for all page data to be loaded when the Angular app initializes - with each page in its own file (to satisfy the designers).

This is what I've been attempting:

var app = angular.module("templatesApp", ['bulletComponent', 'popupComponent', 'imageComponent', 'paragraphComponent', 'ngRoute']);

var numberOfPages = 0;
var pageData = [];
var pageIndex = 0;

/*Factory that uses http.get on content.json, utilized by multiple controllers */
app.factory('content', ['$http', 'completions', 'pages', function($http, completions, pages) {
    var url = 'json/content.json';
    return $http.get(url)
        .success(function(data) {
            // loop through pages and add corresponding page objects to completions.js service
            for (var i=0; i<data.length; i++) {
                completions.addPage(data[i].title);
                numberOfPages += 1;
            }
            loadPageData(pages, completions);
            return data;
        })
        .error(function(data) {
            return data;
        });
}]);

var loadPageData = function(pages, completions) {
    console.log("loadPageData called when pageIndex = "+pageIndex);
    pages.success(function(loadedData) {
        pageData.push(loadedData);
        completions.addPageComponents(pageIndex + 1, pageData[pageData.length-1]); 
        pageIndex += 1;
        if (pageIndex < numberOfPages) {
            loadPageData(pages, completions);
        }
    });
}

app.factory('pages', ['$http', function($http) {
    console.log("pages factory called with pageIndex = "+pageIndex);
    var url = 'json/page'+ (pageIndex + 1) +'.json';
    return $http.get(url)
        .success(function(loadedData) {
            return loadedData;
        })
        .error(function(loadedData) {
            return loadedData;
        });
}]);


/*Controller for menu, retrieves data from factory*/
app.controller('menuCtrl', ['$scope', '$http', 'content', function($scope, $http, content) {

    content.success(function(data) {
        $scope.pages = data;
    });

}]);


/*Controller for individual pages. Makes XHR requests to json pages for data.
  Contains function for computing column widths*/
app.controller('pageCtrl', ['$scope', '$routeParams', '$http', 'content', 'completions', function($scope, $routeParams, $http, content, completions) {

    $scope.page = pageData[$routeParams.pageId-1];

    $scope.getStyle = function(singleCase, device) {
        if (singleCase == undefined)
            return '';

        return assignBootstrap(singleCase, device);
    }    

    $scope.pageId = $routeParams.pageId;
}]);

As you can see, the 'content' factory is invoked by 'menuCtrl'. It first loads the content.json file (a list of the page titles), then it triggers 'loadPageData', a recursive function designed to call the 'pages' factory for each required page as it loads.

The issue arises when the console logs reveal that the 'pages' factory is called only once and PRIOR to the execution of the loadPageData function. Subsequently, each HTML page receives the same initial set of data.

I suspect I am not utilizing the 'pages' factory correctly, but I am unsure about the correct approach.

If anyone has any insights or suggestions, I would greatly appreciate hearing them.

UPDATE
Thank you for the feedback. I believe what I need to figure out is: How can I establish a dynamic chain of promises (using $http calls)? The number of pages will vary, so hard-coding them is not possible.

Answer №1

After experimenting, I found a method that seems to be effective:

app.factory('content', ['$http', 'completions', function($http, completions) {
    var url = 'json/content.js';
    return $http.get(url)
        .success(function(data) {
            // loop through pages and add corresponding page objects to completions.js service
            for (var i=0; i<data.length; i++) {
                completions.addPage(data[i].title);
                numberOfPages += 1;
            }
            // load page .js files
            var tempData = getData(0, completions);            
            for (var i = 1; i < numberOfPages; i++) {
                (function (i) {
                    tempData = tempData.then(function() {
                        return getData(i, completions);
                    });
                }(i));
            }

            return data;
        })
        .error(function(data) {
            return data;
        });
}]);

// function to fetch individual page data and set SCORM objectives
function getData(id, completions) {
    return $.ajax({
        url: 'json/page'+ (id + 1) +'.js',
        dataType: 'json'
    }).done(function(d) {
        // push data into pageData array for later use
        pageData.push(d);

        // register this page's completable components in SCORM
        completions.addPageComponents(id + 1, d);

    }).fail(function() {
        console.log('ERROR loading page index '+id);
    });
}

I initially struggled with $q.all and promises, but was directed to a helpful SO answer by a colleague. When the 'content' factory is invoked, it loads the first .js file using the getData function. The line...

tempData = tempData.then(...

...ensures each load completes before moving on to the next. Storing the loaded data is crucial, as seen in getData.done where data is pushed to pageData for future reference and passed to completions service for setting SCORM objectives.

All systems go!

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

How can I properly retrieve an entry for processing within my route?

Hello everyone! This is my first question on this platform, so please bear with me if I'm missing any important details. I'll add them as soon as possible. I am currently working on setting up a camel route where I retrieve a URL from my Databas ...

Navigate directly to a designated element in a React component without the need to scroll when clicking a link

When viewing a user's profile in React, clicking on an image currently scrolls to that specific image within the entire images page. However, I am looking to modify this behavior so that it navigates directly to the image element without any scrolling ...

Invalid mime type for HTML5 mode

I have successfully set up my redirect, but now all my style sheets are being served as text/html because they are going through core.index. Strangely, I only get this error for style sheets and not for JS files. How can I fix this issue? Error: Res ...

An error has occurred: [$injector:modulerr] Unable to create module xxApp because: Error: [$injector:nomod] Module 'xxApp' does not exist

After running the gulp task to uglify my application controller files, I encountered an error. In a previous project, the same gulp uglify code worked without any issues, but that project did not include any ES6 commands. Now I am using the 'gulp-ugl ...

Generating URL parameters for Ajax requests on the fly

My current project involves creating a dynamic form where the number of fields displayed changes based on the user's selection from a dropdown menu. This means that depending on what option they choose, anywhere from 2 to 20 different fields may be sh ...

I'm having an issue where whenever I click on a different page, I keep getting redirected back to the first page

Upon conducting research, I discovered that by implementing the refined code below, I was able to resolve my issue (my other html was also corrected using this solution) setTimeout(function() { datatable_FTP.ajax.reload(null, false); }, 30000); Although I ...

Organizing outcome searches through ajax

I have a result table displayed on the left side https://i.stack.imgur.com/otaV4.png https://i.stack.imgur.com/pp9m0.png My goal is to transform it into the format shown on the right side of the table In a previous inquiry found here, @Clayton provided ...

Are the props.children handled differently within the <Route> component compared to other React components?

Each and every react component undergoes a process in the following function, which is located in ReactElement.js within node_modules: ReactElement.createElement = function (type, config, children){ . . . } This function also encompasses <Rou ...

Confusion surrounding the concept of returning an arrow function from a Vuex storage getter

I delved into a Vuex course and the journey was smooth sailing until they introduced an arrow function in a getter, then utilized it in a computed property and action. Behold the code: item structure: const _products = [ { id: 1, title: "iPad 4 Mini", ...

Safari is not properly handling element IDs when used in conjunction with React

I am currently in the process of building a straightforward single-page website utilizing React. At the top of the page, there is a navigation bar that contains links to various sections of the site: <li><a href="/#about">About u ...

SPA application utilizing both public and private socket.io connections

My web application caters to two types of users: public users who have yet to authenticate, and private users who are logged in and have authenticated themselves. Using token-based authentication in a single-page app, there are no page refreshes after the ...

Guide to forming an array by extracting specific properties from a nested JSON array using javascript

Currently, I have this list: list = { id: 1, arr: [ {index : 1 , description: "lol" , author: "Arthur"}, {index : 2 , description: "sdadsa" , author: "Bob"}, {index : 3 , desc ...

Having trouble installing gatsby-plugin-transition-link using npm

https://i.stack.imgur.com/DyZxQ.png I'm facing some issues while trying to install gatsby-plugin-transition-link using npm. No matter what solutions I've attempted, the errors persist. Can anyone provide insight into what might be causing this p ...

Page redirects automatically after AJAX call

I'm a beginner when it comes to using AJAX and I am trying to delete a student from a list through an AJAX request. I want the response of the request to be displayed on the same page within a specific div, but instead, the response keeps redirecting ...

Display information from a Google Sheet onto a leaflet map based on specified categories

I am currently facing some challenges while creating a map with markers using data from Google Sheet and leaflet. Despite my efforts, I have encountered a few bugs that are proving to be difficult to resolve: Group Filtering - Although I can successfully ...

Choose the specific Element by its dynamicID in JQuery

Just starting out with Jquery and I have a specific task in mind. In my HTML page, I have elements with IDs generated by concatenating a string variable. My goal is to use JQuery to select the element with this dynamically generated ID. See below for more ...

Upload multiple files at once, edit span text, and retitle to files chosen

I need help updating the span text for each file uploader on my page. I want the default "Choose a file..." text to change to the selected filename. Can someone assist me with this? Here is a Js fiddle that I've been working on. This is my HTML mark ...

Incorporate the npm mqtt package into my Angular application

I'm trying to incorporate the package https://www.npmjs.com/package/mqtt#connect into my Angular project. Since it's not a standard Angular package, I'm unsure of what I need to include in the module and controller to make it function correc ...

Does Leaflet.js provide a method to cycle through all markers currently on the map?

Is there a way to make my map icons scale in size with zoom instead of being a static 38x38? If CSS can achieve this, I'm open to that option as well. It seems like it would also involve iterating through all markers, but I haven't been able to f ...

I am looking to fetch information from a different Firestore collection by looping through data using a forEach method within an onSnapshot function

I'm struggling to grasp the concept of rendering data from Firestore in my project. I've searched extensively but haven't been able to find a solution that fits my requirements. Background Information In my Firestore database, I have collec ...