Utilizing AngularJS with a factory to access JSON data stored within a local file

I'm currently working on adapting an Angular JS example to be functional as a standalone file in a local folder on an offline device. The original example can be viewed here:

After successfully local-linking the necessary libraries and properly referencing the templates, I encountered difficulties loading a local JSON data array (countriesArray) into the countries factory without using HTTP. Initially, I used the example's JSON URL temporarily, but despite that, only a blank screen is displayed due to potential code errors.

Apologies for any lack of understanding on my part.

<html ng-app="countryApp">
      <head>
        <meta charset="utf-8">
        <title>Angular.js Example</title>
        <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script>
        <script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular-route.min.js"></script>
        <script>
          var countryApp = angular.module('countryApp', ['ngRoute']);
      var countriesArray = [
      {
        "name": "China",
        "population": 1359821000,
        "flagURL": "//upload.wikimedia.org/wikipedia/commons/f/fa/Flag_of_the_People%27s_Republic_of_China.svg",
        "capital": "Beijing",
        "gdp": 12261
      },
      {
        "name": "India",
        "population": 1205625000,
        "flagURL": "//upload.wikimedia.org/wikipedia/en/4/41/Flag_of_India.svg",
        "capital": "New Delhi",
        "gdp": 4716
      },
      {
        "name": "United States of America",
        "population": 312247000,
        "flagURL": "//upload.wikimedia.org/wikipedia/en/a/a4/Flag_of_the_United_States.svg",
        "capital": "Washington, D.C.",
        "gdp": 16244
      }
    ];
          countryApp.config(function($routeProvider) {
            $routeProvider.
              when('/', {
                template: '<ul><li ng-repeat="country in countries"><a href="#/{{country.name | encodeURI}}">{{country.name}}</a></li></ul>',
                controller: 'CountryListCtrl'
              }).
              when('/:countryName', {
                template: '<h1>{{country.name}}</h1><ul><li>Flag: <img ng-src="{{country.flagURL}}" width="100"></li><li>Population: {{country.population | number }}</li><li>Capital: {{country.capital}}</li><li>GDP: {{country.gdp | currency }}</li></ul>',
                controller: 'CountryDetailCtrl'
              }).
              otherwise({
                redirectTo: '/'
              });
          });
    
          countryApp.factory('countries', function(){
            function getData(callback){
              $http({
                method: 'GET',
                url: 'http://curran.github.io/screencasts/introToAngular/examples/snapshots/snapshot42/countries.json',
                cache: true
              }).success(callback);
            }
    
            return {
              list: getData,
              find: function(name, callback){
                getData(function(data) {
                  var country = data.filter(function(entry){
                    return entry.name === name;
                  })[0];
                  callback(country);
                });
              }
            };
          });
    
          countryApp.controller('CountryListCtrl', function ($scope, countries){
            countries.list(function(countries) {
              $scope.countries = countries;
            });
          });
    
          countryApp.controller('CountryDetailCtrl', function ($scope, $routeParams, countries){
            countries.find($routeParams.countryName, function(country) {
              $scope.country = country;
            });
          });
    
          countryApp.filter('encodeURI', function(){
            return window.encodeURI;
          });
        </script>
      </head>
      <body>
        <div ng-view>{{countries}}</div>
      </body>
    </html>

Answer №1

To optimize your code, consider moving the array of countries into the factory instead of declaring it as a global variable.

In the getData function of the factory, simply pass the array to your callback instead of making an http call.

Here's how the updated factory looks:

countryApp.factory('countries', function () {

    var countriesArray = [ ... ];

    function getData(callback) {
        return callback(countriesArray);
    }

    return {
        list: getData
    };
});

Check out this related example on JSFiddle


Optimize without callbacks:

Instead of using a callback in the getData function, you can make use of a thenable:

1) Inject $q into your factory as a dependency

2) Modify getData like this:

function getData() {
    return $q.when(countriesArray);
}

The $q.when(countriesArray) statement may seem complex, but it essentially means "return when countriesArray is resolved." Since the data is not asynchronous, the method returns immediately, and $q.when wraps the object into a promise for chaining purposes. As a result, callers can now use getData.then(...)

3) The controller invocation changes to:

countries.list().then(function (countries) {
    $scope.countries = countries;
});

View the updated example on JSFiddle here


Load data from a local JSON file:

If loading data from a separate file appeals to you, simply utilize $http. This approach allows you to retrieve data from a local URL effortlessly:

 function getData() {
    return $http.get('countries.json');
}

Since $http returns a promise, existing calls to getData remain unchanged: getData.then(...)

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

Detecting changes in parent ref with Vue's v-modelIs this

I am struggling to implement two-way binding because I can't determine if the model ref is being changed by the parent or child component. Using watch captures all changes without any indication of the source of the change. <script setup> // Pa ...

Struggling to receive accurate data from every statement

I have an object (known as allUserInfo) that looks like this: Object { available_client_ids: Array[2] 0: "demo" 1: "4532t78" available_client_names: Array[2] 0: "Demo" 1: "Bobs Bakery" email: "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" ...

Adding code containing various Google Maps elements in a fresh browser window using JavaScript

I've encountered an issue while trying to create a new page with a Google map and title based on the button clicked. Interestingly, when I copy/paste the HTML in the "newhtml" variable into an actual HTML file, it works perfectly fine. However, it doe ...

Raycasting in Three.js is ineffective on an object in motion

Working on a project that combines three.js and typescript, I encountered an issue while attempting to color a sphere by raycasting to it. The problem arises when the object moves - the raycast doesn't seem to acknowledge the new position of the objec ...

"Learn the method of connecting a dynamic value to an input field through the use of ng-repeat and ng

I've encountered an issue trying to bind a value to an input in Angular. I initialized the 'object[component.name]' first and then assigned that value to ng-model. This was necessary because I needed to bind the value from ng-repeat, but it& ...

What could be causing the value of response.name to be undefined in this situation?

Despite extensively searching through various StackOverflow threads, none of the suggested solutions seemed to work for my specific scenario. Upon analyzing the response using console.log(response), I received an "Object Object" message. I am puzzled as to ...

transferring information to a PHP page using JavaScript without using AJAX requests or form submissions

I am currently working on a PHP page where I receive POST data using some functions, without relying on AJAX for page refresh. At the moment, I have a form that includes hidden fields holding dynamic data, which is then sent using JS like this: document.m ...

Modify a single row within a column with Jquery

I have been working on a project that involves using jQuery with JSON data to populate an HTML table. However, I am facing an issue where when I try to do some inserts, I need to update multiple rows in one column, but it is not functioning as expected - i ...

The updating of input and output does not happen instantly; there is a delay before changes

Having an issue with updating input values in React. When using the setState method, the console log does not show the updated input value immediately. For instance, typing "a n" into the input only logs "a" after the second keystroke... Although I under ...

Choosing a JSON item based on its numerical position rather than by its name

I am attempting to store a JSON object containing information in multiple languages. I am uncertain if the way I have implemented it is optimal, so any suggestions are appreciated. My current issue is that I am unsure how to access the first language with ...

Enhance your 3D models with react-three-fiber's canvas modification capabilities

I am looking to modify the model function within the canvas. Currently, I have two separate Models (functions in js files) named Model1 and Model2. Both Models have the ability to outline the mesh when hovered over. The existing code structure is as follow ...

Updating the current view in Rails with newly fetched data

NOTE: To make it easier, skip to the EDIT part below. Thank you! I am currently working on adding a simple feature to my app. The feature involves a view with a chart that depends on two query parameters: :from and :to. I am using "Chartkick" and below a ...

Engage in a sequence of actions by tapping and retapping on a div element

Is there a way to toggle the color of an element from black to orange with a single click and back again with another click? Additionally, I have set up a hover effect in CSS that changes the color to orange when hovered over. In my current code, the elem ...

Reduce the amount of code in conditional statements

Is there a way to streamline the following code- <div className="App"> <Checkbox parameter={parameter1} setParameter={setParameter1}></Checkbox> { parameter1.country && parameter1.category ? < ...

Class selectors can be used for jQuery drag and drop functionality

Seeking help from experienced individuals, as I am new to JS/jQuery. I have come across a script for drag and copy functionality which I have customized to fit my needs. However, the script currently uses "id" selectors and I wish to switch to using "class ...

Encountering a Module Error in AngularJS and Laravel Blade when Altering the interpolateProvider (Delimiter)

I am facing a peculiar issue when I try to integrate Laravel 5 (with Blade) and Angular 1.3 together. While I am well-versed with Laravel, I am relatively new to Angular. I understand that in order to make Angular work seamlessly with Laravel's Blade ...

Error: Unable to access the 'trim' property of an undefined value in Firebase functions for Node.js

After running my code, I encountered an issue with the validation of addCustomer Details. The validators I used involved a reducer function. When attempting to post data in Postman using the following format: { "bio" : "Devon", &q ...

Looking for a way to add a permanent footer to the bottom of your webpage without affecting the tab order for accessibility?

I have a paginated form with a fixed navigation footer at the bottom that needs to stay in place even when scrolling. This footer should also be at the bottom of the page for mobile devices and tablets. To achieve this, I used position: fixed on the foote ...

There seems to be an issue with the cookie functionality as it is not

My code for setting and getting Cookies is as follows: $.setCookie = function (c_name, value, exdays) { var exdate = new Date(); exdate.setDate(exdate.getDate() + exdays); var c_value = escape(value) + ((exdays == null) ? "" : "; expires=" + e ...

Maintain structure when using json_decode() within a for loop

When working with JSON files and using json_decode in a loop to identify specific cases, I discovered that my current function requires two separate loops to capture all the cases. However, I am looking for a way to achieve this within a single iteration. ...