Sam Croft

Full-stack developer

Loading JSON data into an Ionic app using Angular JS’ $http service

  • 31 comments

Filed in: angular, api, cordova, ionic, javascript

Ionic Framework and Angular JS logo

Several years ago I wrote an article about loading data into a PhoneGap app. The article detailed using jQuery’s $ajax method to load JSON data into a simple PhoneGap app. People are still commenting on this article today, so I figured I’d write an up to date version on the same subject, but based around Ionic.

I’ve been working with Ionic a lot of last couple of months. I love it. Using it has gotten me all excited again about hybrid app development. So I thought I’d get back into writing and talk about how I use Angular JS’ $http service to load data into an Ionic app.

This article is split into two parts:

  1. Explanation and code examples for loading data using Angular JS’ $http service.
  2. How this can be applied to load data into an Ionic app, with a full example.

Full example app on GitHub

TL;DR

The abridged version of this article:

//a factory
angular
    .module('app')
    .factory('SomeDataFactory', function($http){
        var url = 'http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK';

        return {
            getSomeData: function(){
                return $http.jsonp(url);
            }
        }
    });

//a controller
angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        SomeDataFactory.getSomeData().then(function(response){
            //do something with response
            _this.data = response.data;
        }).catch(function(response){
        	//handle the error
        });
    });

A note on using controller as and this instead of $scope

Throughout this article I use this instead of $scope. This is just my preference. I prefer using the controller as method, removing the requirement of having to inject the $scope dependency into my Controllers and also decoupling my controller logic from the Angular $scope object. John Pappa has a great article about the two different approaches. Dave Ceddia also has a great read about killing $scope that you should check out.

Using Angular JS’ $http service to request data from a remote server

Angular provides a service for making requests to http servers, aptly named the $http service. Roughly speaking this is similar to jQuery’s $ajax method in that it uses a promise interface to return a response and/or relevant status responses.

There are two common ways of using the $http service in an Ionic app; directly within a Controller or separated out into a Factory.

What is the $http service and how does it work?

The $http service is a core Angular service that facilitates communication with the remote HTTP servers via the browser’s XMLHttpRequest object or via jsonp.

Angular JS: $http documentation

The $http service is a function that returns a Promise to handle a response. The Promise object allows you to execute code when something has been resolved/rejected and finished. For the purpose of this article that will be doing something when we have a response from the server. This response includes any data returned by the server, success/error codes and header information.

Use of the $http service will typically look something like this:

$http({
    method:'GET',
    url:'http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK'
}).then(function(response){
    //success
    //do something with the response
}, function(response){
    //error
    //show an appropriate message
});

Let’s look at two ways you could use the $http service in an Angular app.

Using the $http service directly in a Controller

Initially this may seem the best approach; simply inject the $http service into your Controller and you can directly make server requests:

angular
    .module('app')
    .controller('SomeController', function($http){
        var _this = this;

        $http.jsonp('http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK').then(function(response){
            _this.yourData = response.data;
        });
    });

As the $http service returns a Promise, this could also be written as:

angular
    .module('app')
    .controller('SomeController', function($http){
        var _this = this;

        var someData = $http.jsonp('http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK');

        someData.then(function(response){
            _this.yourData = response.data;
        });
    });

In this example I am using the jsonp shortcut method of the $http service. Most apps will deal exclusively with JSON, so I figured this is the best example. Using jsonp we have the benefit of being able to make cross server origin requests in our browser—providing the end point supports jsonp of course.

This is the equivalent of using the $http service with a configuration object, setting jsonp as the method:

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        $http({method:'jsonp',url:'http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK'}).then(function(response){
            _this.yourData = response.data;
        });
    });

That’s a bit longwinded though, so I will use the jsonp shortcut method in all further examples.

Using the JSONp callback parameter

The callback parameter is required to make jsonp requests. It must have a value set to JSON_CALLBACK. The addition of this parameter makes Angular wrap an id around each of your server requests. The same id is then returned within the server response, to facilitate cross domain requests. This is important; Without it jsonp requests will fail. If you open your developer console and check the network tab you can see what Angular does with this parameter and how it affects your response.

Anyway, back to the example. This looks good, it does the job directly in your Controller. But there is a better way; using a Factory.

Using the $http service in an Angular Factory

Using the $http service in an Angular Factory is the recommended way of making requests to a server. There are two clear benefits for using an Angular Factory:

  1. Separates the data layer of your app from your Controller logic, making your application easier to manage.
  2. Makes the data layer reusable within other Controllers.

What is an Angular Factory?

An Angular Factory is an object literal that can be injected into any Controller. Consider the following simple Factory:

angular
    .module('app')
    .factory('SomeDataFactory', function(){
        var someData = {
            some: 'thing',
            lots_of_things: [
                'thing',
                'other thing'
            ]
        };

        return {
            getSomeData: function(){
                return someData;
            }
        }
    });

Here we have a Factory with a public method, getSomeData that returns… some data. We can then inject this Factory into a Controller to access the data via the public method:

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        this.data = SomeDataFactory.getSomeData();
    });

Note: as this example is just returning an object – we don’t need to worry about handling a Promise.

That keeps things nice and organised and using this approach with the $http service is very cool.

Creating an Angular Factory for your Ionic app

Using this method it’s easy to create a reusable data layer for your app.

Setting up the Factory

In its simplest form we just need a a single method that returns a Promise from an $http service request:

angular
    .module('app')
    .factory('SomeDataFactory', function($http){
        var url = 'http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK';

        return {
            getSomeData: function(){
                return $http.jsonp(url);
            }
        }
    });

Looking at this we have a Factory, SomeDataFactory, and are injecting the $http service as a dependency.

The Factory returns an object literal, which means that our Controller can access its public methods—in this case the method getSomeData. Remember here that the $http service is going to return a Promise. We can then handle the promise in our Controller.

Injecting the Factory into a Controller as a dependency and using the promise interface to access the data

Looking at our Controller we’d have something like this:

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        SomeDataFactory.getSomeData().then(function(response){
            //do something with response
            _this.data = response.data;
        });
    });

Here we have a controller, SomeController, with our Factory, SomeDataFactory, injected as a dependency. As the Factory is an object literal we can access the public method, getSomeData. To access the response from the server we need to use the then method of the returned promise interface, which will contain the response parameter containing the response from the server. Remember, the then method only executes after the $http service resolves or is rejected.

This leads onto something interesting about Promises; do we want to handle the promise within the Factory, the Controller… or both?

In the above example I’m handling it within the Controller. This is good as it means if there is an error I can handle it and show an appropriate message to the user. But there are cases where we may like/need to handle the promise within the Factory; maybe we need to check something in the data, do some operations and then return modified/additional data. We can do that with a few changes to our Factory and Controller:

angular
    .module('app')
    .factory('SomeDataFactory', function($http){
        var url = 'http://samcroft.co.uk/json-data/sample?callback=JSON_CALLBACK';

        return {
            getSomeData: function(){
                return $http.jsonp(url).then(function(response){
                    var data = response.data;

                    //do something exciting with the data

                    return data;
                });
            }
        }
    });

With this change to the Factory I am only returning a data object, not the full response object that is returned by the $http service. However, within our controller we will still be dealing with a promise as we’re still calling the $http service, just changing the return value of the response itself.

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        SomeDataFactory.getSomeData().then(function(data){
            _this.data = data;
        });
    });

So now there are two Promises, chained together, one in the Factory and one in the Controller. The Promise in the Controller will not be resolved until our data object is returned from the Factory.

This can be really useful, but from this point onwards I will revert back to returning the full response to the Controller.

We also need to catch any errors. We can do this by passing a second function to the then method within the Controller:

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        SomeDataFactory.getSomeData().then(function(response){
            //request was successful
            _this.data = response.data;
        }, function(response){
            //request was not successful
            //handle the error
        });
    });

Alternatively we can use the catch method of our promise:

angular
    .module('app')
    .controller('SomeController', function(SomeDataFactory){
        var _this = this;

        SomeDataFactory.getSomeData().then(function(response){
            //request was successful
            _this.data = response.data;
        }).catch(function(response){
            //request was not successful
            //handle the error
        });
    });

I find this method easier to read, but both will do the same thing.

Now on to the fun stuff, using this within an Ionic app!

Loading data into an Ionic app – with a full example

Using the above examples it’s really simple to apply this method of loading data to your Ionic app. In fact, very little needs to change.

Putting this into practice I’ll go through a simple app that loads data in one view, a list of items, and allows you to click each one and change view to show more data about the selected item.

To give a bit of context; the first view will load a list a few comics (I like comics) – some of the new Marvel Star Wars comics (I like Star Wars). Each comic will navigate to another view that displays more detail about the comic.

Creating the app

I’m going to use the Ionic CLI to create a a blank Ionic app to get things quickly setup:

$ ionic start comicsApp blank

When the Ionic CLI has finished I’m going to create four additional files. A file for our controllers:

www/js/controllers.js

A file for our Factory service:

www/js/services.js

A file for our first view to list all the comics:

www/templates/comics.html

Finally, a file for our second view to list additional comic details:

www/templates/comic-details.html

This follows the file convention that you will likely see on other Ionic apps, or if you use the tabs or sidemenu templates via the CLI.

I then need to make a few changes to the index.html file:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="css/style.css" rel="stylesheet">

    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <script src="cordova.js"></script>

    <script src="js/app.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/services.js"></script>
  </head>
  <body ng-app="comicsApp">

    <ion-nav-bar class="bar-stable">
      <ion-nav-back-button>
      </ion-nav-back-button>
    </ion-nav-bar>

    <ion-nav-view></ion-nav-view>
  </body>
</html>

I’ve highlighted the changes and additions:

  • Lines 16-17 – include controllers.js and services.js
  • Line 19 – change the app module name from starter to comicsApp
  • Lines 21-24 – add the ion-nav-bar and ion-nav-back-button elements
  • Line 26 – add the ion-nav-view element

Setting up the views

Next up we need to set up the routing for our views. We can do this by adding a config block after the run block in www/js/app.js. We also need to update the name of our module that we changed earlier in our index.html file from starter to comicsApp:

After the run block (removed below) we can then add two simple routes:

angular
    .module('comicsApp', ['ionic'])
        .run(function($ionicPlatform) {
            // ...
        })
        .config(function($stateProvider, $urlRouterProvider) {
            $stateProvider
                .state('comics', {
                    url: '/comics',
                    templateUrl: 'templates/comics.html',
                    controller: 'ComicsController',
                    controllerAs: 'comics'
                })
                .state('comic-detail', {
                    url: '/comics/:comicId',
                    templateUrl: 'templates/comic-detail.html',
                    controller: 'ComicDetailController',
                    controllerAs: 'comicDetail'
                });

            $urlRouterProvider.otherwise('/comics');
        });

Nothing fancy here, just two views – the second of which has a state parameter comicId – that’s important, but we’ll come to that in a bit.

Note that the view template url is a relative path to the two view files we created earlier, while the controllers will resolve by their function name, rather than a path.

As mentioned earlier, I am using the controllerAs method instead of using $scope. This is just my preference.

Creating the Factory

Before creating the Controllers I’m going to make a simple Factory that uses the methods explained above. The factory is going to contain two public methods:

  1. getComics – to fetch all of the comics.
  2. getComic – to fetch detail for a specific comic, by comic id.

Within www/js/services.js we can add a simple Factory with these methods:

angular
    .module('comicsApp')
    .factory('Comics', function($http) {
        var dataSource = 'http://samcroft.co.uk/comics-app/comics?callback=JSON_CALLBACK';

        return {
            getComics: function() {
                return $http.jsonp(dataSource);
            },
            getComic: function(comicId) {
                return $http.jsonp(dataSource, {
                    params: {
                        id: comicId
                    }
                });
            }
        }
    });

Everything here is pretty much the same as I’ve discussed before, with the exception of using the $http service’s params object to pass additional data, in this case the comic id, which will create the required query string i.e. ?id=x (more on this in a bit).

Using the $http service’s params object

The params object is an object that you can pass to the $http service that contains a list of key/value pairs, used to create a query string. In this case we will need to pass the id of a comic, comicId, to the getComic method. This will generate a url like http://samcroft.co.uk/comics-app/comics?id=23

It’s not a requirement to use the params object, you can concatenate a url manually – but this is a cleaner and easier to read way.

Create the controllers and views

Now we have the Factory setup we can create the controllers and views. I’ll go through each one separately.

Creating a controller to get all of the comics

This controller will be used to obtain a list of all the comics. Let’s add this in www/js/controllers.js:

angular
    .module('comicsApp')
    .controller('ComicsController', function(Comics) {
        var _this = this;

        Comics.getComics().then(function(response){
            _this.comics = response.data;
        }).catch(function(response){
            //request was not successful
            //handle the error
        });
    });

First of all we need access to the Comics Factory, so we need to inject this as a dependency (line 3).

Now that we have access to the Comics Factory we can call the public method getComics. As this uses Angular JS’ $http service this will return a promise, so we can use the then method to do something when the http request has resolved (or been rejected). In this case I’m just assigning the response data object to a property, comics. The response for this request will be an array of JSON objects with an id and title for each comic:

[
    {
        "id": 19242,
        "title": "Star Wars"
    }, 
    {
        "id": 19379,
        "title": "Darth Vader"
    }, 
    {
        "id": 19631,
        "title": "Princess Leia"
    }, 
    {
        "id": 19486,
        "title": "Kanan The Last Padawan"
    }
]

Creating an Ionic view to list all of the comics

Now that we’ve assigned the server response to a property we can access it in the view to create a list of all of the comics. As the data is an array of objects it’s simple to iterate through each item in an Ionic view by using Angular’s ng-repeat directive. We can add this in our first view file, www/templates/comics.html:

<ion-view view-title="Comics">
    <ion-content class="padding">
        <div class="list">
            <a ng-href="#/comics/{{ comic.id }}" class="item" ng-repeat="comic in comics.comics">
                {{ comic.title }}
            </a>
        </div>
    </ion-content>
</ion-view>

On line 4 I am using the ng-repeat directive to say; loop through each object in the comics array and assign it to a variable called comic. Using this variable I can then access properties from the comic object and output markup by using Angular’s double curly brace notation. In this case, on line 5, just the comic’s title.

Using Ionic’s CSS components

I should note that I am using Ionic’s awesome CSS components to create basic styled lists in each view.

Reminder: I’m using the controller as method (instead of using $scope) so I need to reference the name that I have assigned to my controller, before I can access any properties or methods. In this case I set the reference to my controller as comics. This also happens to be name of the property that I have assigned the array to, which is why I needed to write comics.comics within the ng-repeat expression.

I also need to access the comic’s id and use that in the url for the comic detail page. I do this on line 4 using the ng-href directive and again use double curly braces to output the value into the markup.

Note: when creating dynamic links it’s always best to use the ng-href directive instead of html’s href attribute.

Now that this is setup when a user selects one of the comics the url is going to change from #/comics to #/comics/x, where x is the id of the selected comic. This is really important for the next step.

As an aside, the clever thing about this is that whenever anything changes in the comics array, such as an object being removed or added, the view will automatically update the list. There is no need to tell it to be refreshed, it will just do it. That’s not so important for the purpose of this article, but it’s a powerful thing to bear in mind.

Creating a controller to load details of a single comic

When a comic is tapped we want to change view and load more information about that comic. The ComicDetailController is going to handle the loading of this additional information. Let’s add another controller to www/js/controllers.js:

.controller('ComicDetailController', function(Comics, $stateParams) {
        var _this = this;
    
        Comics.getComic($stateParams.comicId).then(function(response){
            _this.comic = response.data;
        }).catch(function(response){
            //request was not successful
            //handle the error
        });
    });

This is almost identical to the ComicsController we created earlier but has the addition of passing a parameter to the Factory to specify which comic we want more detail about—the comic’s id. To access the comic id we need to inject Angular’s $stateParams service (line 3), in addition to the Comics Factory. The $stateParams service can be used to obtain the id that was requested in the navigated url, in this case the parameter comicId. Remember this parameter was configured earlier within the routes.

The Comics Factory method getComic is going to return a single JSON response with additional information about the selected comic and assign it to a property, comic. For example:

{
    "id": 19242,
    "title": "Star Wars",
    "description": "Following the heroes of the Rebel Alliance between the events of Star Wars: Episode IV A New Hope and Star Wars: Episode V The Empire Strikes Back.",
    "characters": [
        "Luke Skywalker", 
        "Han Solo", 
        "Princess Leia Organa", 
        "Chewbacca", 
        "R2-D2", 
        "C-3PO"
    ]
}

We now have the comic description and an array of characters in addition to the id and title.

Creating an Ionic view to show the additional comic details

With the additional comic information we can create a simple view to display the details in the view file www/templates/comic-details.html:

<ion-view>
    <ion-nav-title>{{ comicDetail.comic.title }}</ion-nav-title>
    <ion-content class="padding">
        <p>{{ comicDetail.comic.description }}</p>

        <div class="list">
            <div class="item" ng-repeat="character in comicDetail.comic.characters">{{ character }}</div>
        </div>
    </ion-content>
</ion-view>

There are a few things going on in this view:

  • Line 2 – using Ionic’s ion-nav-title directive to set the title of the view
  • Line 4 – displaying the comic description
  • Line 7 – using Angular’s ng-repeat directive to iterate through each character in the characters array and list their name

And there we go – a really simple app that demonstrates loading data into views using Angular’s $http service.

Some things to bear in mind

As with everything there are a few things that you should bear in mind:

  • Ionic caches views by default.
  • A loading indicator should be used while data is being loaded into the app.

Ionic caches views by default

By default Ionic will cache your views to improve performance. This is a good thing but can pose a problem when dealing with loading data that you may not wish to cache. At the moment the controller, view and requested data will only be loaded once, when they are initially requested. This could be perfectly acceptable and in the context of this app that’s probably a good thing as it’s not something you’d expect to change between changing views.

However, if you are dealing with live data there is a couple of ways around this; disabling view caching or using Ionic’s view events, to trigger when you want data to be loaded.

Disabling views from caching

There are two ways you can disable view caching. Either within the ion-view element, by setting the cache-view attribute:

<ion-view cache-view="false" view-title="My data">
</ion-view>

Or within the state provider, by setting the cache property in the config block of www/js/app.js:

$stateProvider.state('comics', {
	cache: false,
	url: '/comics',
	templateUrl: 'templates/comics.html',
	controller: 'ComicsController',
	controllerAs: 'comics'
});

Both will achieve the same thing—prevent the view and controller from caching.

Using Ionic’s view lifecycle events to trigger data requests

As an alternative (or an addition) to disabling caching, Ionic views have lifecycle events that can be used in your controllers to determine when a method should be executed. For the purpose of this app they can be used to trigger when we want the data to be loaded into the view.

We can use the enter view lifecycle event to change our code so that the request to load data is triggered when the view has entered and is the active view:

angular
    .module('comicsApp')
    .controller('ComicsController', function(Comics, $scope) {
        var _this = this;

        $scope.$on('$ionicView.enter', function(){
            Comics.getComics().then(function(response){
                _this.comics = response.data;
            }).catch(function(response){
                //request was not successful
                //handle the error
            });
        });
    });

There are two changes here:

  • Line 3 – injecting the $scope object into the controller.
  • Line 6 – moving the data request inside of the Ionic view enter event.

As well as removing the requirement to disable the view from caching we also have the benefit of data only being requested once the view has fully entered and is active. This is very useful if you are using view transitions as loading data mid-transition (as would happen by default if using the above methods) can cause a bit of a stutter in your app.

Showing a loading indicator while data is being loaded

It’s always good practice to show a loading indicator while data is being loaded into your app. Ionic has a great platform specific loading indicator that is very easy to use with this technique of loading data. To use it we just need to inject the dependency into our controller, display the loading indicator before the data is requested and hide it when the promise is resolved or rejected:

angular
    .module('comicsApp')
    .controller('ComicsController', function(Comics, $scope, $ionicLoading) {
        var _this = this;

        $scope.$on('$ionicView.enter', function(){
            $ionicLoading.show();

            Comics.getComics().then(function(response){
                _this.comics = response.data;
            }).catch(function(response){
                //request was not successful
                //handle the error
            }).finally(function(){
                $ionicLoading.hide();
            });
        });
    });

There are three changes here:

  • Line 3 – the $ionicLoading service is injected as a dependency.
  • Line 7 – the loading indicator is displayed by calling the show method.
  • Lines 11–12 – the loading indicator is removed by calling the hide method within the finally method of our promise.

Full example app on GitHub

The end result should be a simple app with two views that you can navigation between:

Animated gif app demo

About the author

I'm Sam Croft a full-stack developer with over 15 years experience in web and app development. For the last six years I have been a partner of Running in the Halls, an app and game design studio based in Huddersfield, UK. During this time I have developed many web and applications. Highlights include a node.js/socket.io app to create the worlds largest crowd-based game on the first series of Channel 4's Gadget Man with Stephen Fry and Librarygame, a Library gamification platform for Universities. Librarygame is being played by over 6,000 students at The Open University, The University of Manchester, The University of Glasgow and The University of Huddersfield.

In my spare time I enjoy long distance running, watching all sports (especially F1) and playing video games. I live in the Holme Valley in West Yorkshire with my wife, Alex.

Sometimes I tweet.

  • Amit Gupta

    Hello Sam,

    Thanks for such a wonderful article of loading JSON data into an Ionic app using Angular JS $http service. It is helping me a lot in learning ionic framework.

    I able to configure it locally on my system and data is successfully loading with your external url http://samcroft.co.uk/comics-app/comics?callback=JSON_CALLBACK

    But when I try to use my localhost url in place of it then it never loads data. I tried to make json file with below data :-

    JSON_CALLBACK([{“id”:19242,”title”:”Star
    Wars”},{“id”:19379,”title”:”Darth Vader”},{“id”:19631,”title”:”Princess
    Leia”},{“id”:19486,”title”:”Kanan The Last Padawan”}])

    Its similar to the data present in external url provided by you but data never loads.

    Please help me telling its solution.

  • Hi Amit,

    How are you creating the JSON in your local file? Are you using PHP? You will need to generate the JSON_CALLBACK variable in the JSON response based on the value that Angular passes. If you’re using PHP you would need to do something like this https://gist.github.com/samcroft/aa9e302e4b5bb9ee4586994f799b10a6

    This will wrap your JSON response in the necessary value for Angular. I wrote a bit about it in this article http://samcroft.co.uk/2014/php-json-encode-decode-functions-tutorial/

    I hope that helps

  • Amit Gupta

    Yes Sam, I am using PHP and want to fetch data from mysql table. I have created comics table with two columns; id and title. And wrote the below PHP code :-

    $sql = “SELECT * FROM comics order by rand()”;
    $result = $conn->query($sql);
    $outp = “”;
    while($rs = $result->fetch_array(MYSQLI_ASSOC)) {
    if ($outp != “”) {$outp .= “,”;}
    $outp .= ‘{“id”:’ . $rs[“id”] . ‘,’;
    $outp .= ‘”title”:”‘ . $rs[“title”] . ‘”}’;

    }
    $outp =’JSON_CALLBACK([‘.$outp.’])’;
    $conn->close();
    echo($outp);

    Output:-
    JSON_CALLBACK([{“id”:3,”title”:”Princess Leia”},{“id”:1,”title”:”Star
    Wars”},{“id”:2,”title”:”Darth Vader”},{“id”:4,”title”:”Kanan The Last
    Padawan”}])

    Please let me know if anything needs to be updated in my php code so that data starts coming.

    Thanks a lot Sam for your help…

  • Amit Gupta

    Hello Sam, After struggling a bit, I able to get correct output from my mysql comics table. I updated my PHP code a bit as given below :-

    header(‘Content-Type: application/json’);
    header(“Access-Control-Allow-Origin: *”);

    $mysql_host = “localhost”;
    $mysql_database = “ionic”;
    $mysql_user = “root”;
    $mysql_password = “”;

    // Create connection
    $conn = new mysqli($mysql_host, $mysql_user, $mysql_password,$mysql_database);

    // Check connection
    if ($conn->connect_error) {
    die(“Connection failed: ” . $conn->connect_error);
    }

    $callback = isset($_GET[‘callback’]) ? $_GET[‘callback’] : false;

    $sql = “SELECT * FROM comics”;
    $result = $conn->query($sql);
    $outp = “”;

    while($rs = $result->fetch_array(MYSQLI_ASSOC)) {

    if ($outp != “”) {$outp .= “,”;}
    $outp .= ‘{“id”:’. $rs[“id”].’,’;
    $outp .= ‘”title”:”‘. $rs[“title”].'”}’;
    }

    $output = json_encode($outp);
    $output =”[“.$output.”]”;
    $output = str_replace(‘[“‘,'[‘,$output);
    $output = str_replace(‘”]’,’]’,$output);
    $output = str_replace(‘”‘,'”‘,$output);

    if ($callback) {
    echo sprintf(‘%s(%s)’, $callback, $output);
    } else {
    echo $output;
    }

    Please throw some light on comics detail page. How the comics data coming in detail page http://localhost:8100/#/comics/19242

    Do I make another description column in my comics table and fetch that from json array?

    Sam, please explain when you will be free. I shall be very thankful to you…

    Your affectionate,
    Amit Gupta

  • Hi Amit,
    Yes, you could make a description column an use that for the comics details page. Just use the comic id in your select query to get the corresponding comic.

  • Amit Gupta

    Hello Sam,

    I still finding it tough to get results in comics detail page. Please help me.

    Below code works for me to fetch all comics but not a particular one :-

    $callback = isset($_GET[‘callback’]) ? $_GET[‘callback’] : false;

    if ($callback) {

    // Result is fine. All comics are displaying…

    } else {

    // Code for selected Comic
    $sql = “SELECT * FROM comics where id = 1”; // assume comic id is 1
    $result = $conn->query($sql);
    $outp = “”;
    while($rs = $result->fetch_array(MYSQLI_ASSOC)) {
    if ($outp != “”) {$outp .= “,”;}
    $outp .= ‘{“id”:’. $rs[“id”].’,’;
    $outp .= ‘”title”:”‘. $rs[“title”].'”,’;
    $outp .= ‘”description”:”‘. $rs[“description”].'”,’;
    $outp .= ‘”characters”:[‘. $rs[“characters”].’]}’;

    $output = json_encode($outp);

    $output = str_replace(‘”‘,'”‘,$output);
    $output = str_replace(‘”{‘,'{‘,$output);
    $output = str_replace(‘}”‘,’}’,$output);

    echo $output;
    }

    Though the output is same as coming in your comics detail page link :- http://samcroft.co.uk/comics-app/comics/19242?callback=JSON_CALLBACK

    But data never comes in comic detail page in app (localhost).

    Please help me.. I stuck here from the last 2 days :(

  • Have you checked the Javascript console log for errors? Check the network tab to see if the data being loaded is correct.

    It doesn’t look like you are outputting the callback parameter from Angular. You must include your json response within the callback parameter. Something like:

    if ($callback) {
    echo sprintf(‘%s(%s)’, $callback, $output);
    } else {
    echo $output;
    }

  • Amit Gupta

    Yeh data seems to be loading correctly in network tab.. And first time also data is loading in comics detail page.

    In network tab :- comics?callback=angular.callbacks._1&id=19242

    Json data :-

    angular.callbacks._1({“id”:19242,”title”:”Star Wars”,”description”:”Following the heroes of the Rebel Alliance between the events of Star Wars: Episode IV A New Hope and Star Wars: Episode V The Empire Strikes Back.”,”characters”:[“Luke Skywalker”,”Han Solo”,”Princess Leia Organa”,”Chewbacca”,”R2-D2″,”C-3PO”]})
    Output in App :- Screenshot attached.

    But data never comes when I click on 2nd time or more. After deleting cookies data comes again for first time only.

    callbacks keeps on increasing like angular.callbacks._1, angular.callbacks._2 and so on with every click…

    Can you share your PHP files and MySql tables that generates backend link for the app :- http://samcroft.co.uk/comics-app/comics?callback=JSON_CALLBACK

  • Bernd Birkicht

    Sam, this tutorial was awsome, cause it explains very well various possibilities for using services located in separate files in combination with promises, which are important while using $http. Excellent! I would recommend to handle the response inside the service when the datavolume is high (ie 5000 “records”). I was using a fake REST API ( ie http://jsonplaceholder.typicode.com/photos) instead of a JSON file. Otherwise Google Chrome could show a popup with “process is not responding anymore. Would you like to wait or cancel?”. Anyways your tutorial saved me a lot of time and I can tell my students having a look on it!

  • Hi Bernd,

    Thank you for your reply, I’m glad that you have found it useful. It’s certainly a topic that took me a while to fully understand!

    That’s an interesting comment about high data volume. In this instance it would perhaps be worth using $http’s timeout config property? https://docs.angularjs.org/api/ng/service/$http#usage

  • Veysel Kaya

    Thank you so much..:)

  • Vishal Jagtap

    Hello sam.. Thanks for such a wonderful example. Actually i was implemented it using my external json url,but whenever i have to go details page it give 404 status error for external json url in console,actually data is loaded in network tab.please find attached image for that.. waiting for your reply

  • Hi Vishal, it says data: undefined in your screenshot. If you open the url in a browser, does it return json?

  • Vishal Jagtap

    Thanks for replying
    yes data return by json in browser. there is no
    problem with data. actually first time (comic listing page)data bind to
    ionic view,but when i am click on specific comic it goes to comic
    details page and shows empty listing no data as per i have attached
    previous screen shot…!!!
    for more reference please see attached screen shots

    1st screen shot===> Comic Listing Page With Data(No problem)

    2nd screen shot===> Comic Details Page with empty data(Problem…!!!!)

  • Oliver134

    Hello Sam. Thank you for the tutorial. I did everything, but how to make a video to show such a link:

    Video not show
    Please help me telling its solution. Thank you

  • Oliver134

    but show curently

  • anjali jibhakate

    hi Sam ..Please do reply on Amit’s query…m also strugling through it….
    thanks..

  • Hi Amit,

    Apologies for the delay in replying, I did not see this comment.

    I’m not sure what is happening with your data. If it is loading in your network tab then it should all be working correctly. Perhaps there is an error in your code elsewhere? Have you tried adding some console.log or console.debug statements in your code?

    I’m afraid I do not have any PHP files or MySQL table to share as such. I didn’t create a backend for this article, I just used some hardcoded JSON responses. Something like this https://gist.github.com/samcroft/888f9d09e9e7e31935d8145ded4d4c66

  • Hi Anjali, I have replied.

  • anjali jibhakate

    thanks sam….!! I will again disturb u if i got errors..;)

  • anjali jibhakate

    connect_error) {
    die(“Connection failed: ” . $conn->connect_error);
    }

    $callback = isset($_GET[‘callback’]) ? $_GET[‘callback’] : false;
    $comicId = isset($_GET[‘id’]) && is_numeric($_GET[‘id’]) ? $_GET[‘id’] : null;

    $sql = “SELECT * FROM comics”;
    $result = $conn->query($sql);
    $outp = “”;

    while($rs = $result->fetch_array(MYSQLI_ASSOC)) {

    if ($outp != “”) {$outp .= “,”;}

    $outp .= ‘{“id” : ‘. $rs[“id”] .’,’;
    $outp .= ‘”title”:”‘. $rs[“title”].'”}’;
    }

    $output = json_encode($outp);
    $output =”[“.$output.”]”;
    $output = str_replace(‘[“‘,'[‘,$output);
    $output = str_replace(‘”]’,’]’,$output);
    $output = str_replace(‘”‘,'”‘,$output);

    if ($callback) {
    // Result is fine. All comics are displaying…
    echo sprintf(‘%s(%s)’, $callback, $output);
    }
    else {
    // Code for selected Comic
    $sql = “SELECT * FROM comics where id = 1”; // assume comic id is 1
    $result = $conn->query($sql);
    $outp = “”;
    while($rs = $result->fetch_array(MYSQLI_ASSOC)) {
    if ($outp != “”) {$outp .= “,”;}
    $outp .= ‘{“id”:’. $rs[“id”].’,’;
    $outp .= ‘”title”:”‘. $rs[“title”].'”,’;
    $outp .= ‘”description”:”‘. $rs[“description”].'”,’;
    $outp .= ‘”characters”:[‘. $rs[“characters”].’]}’;
    }
    $output = json_encode($outp);

    /*$output = str_replace(‘”‘,'”‘,$output);
    $output = str_replace(‘”{‘,'{‘,$output);
    $output = str_replace(‘}”‘,’}’,$output);*/
    $output =”[“.$output.”]”;
    $output = str_replace(‘[“‘,'[‘,$output);
    $output = str_replace(‘”]’,’]’,$output);
    $output = str_replace(‘”‘,'”‘,$output);

    echo $output;

    }
    ?>

  • anjali jibhakate

    hi sam …

    this is what i’m doing right now….., and i could not understand how to get specific id and fetch its record….. could u please help me do this…

    thanks again

  • Hi,

    You can simplify things a lot with something like this:

    https://gist.github.com/samcroft/6676d2748b25aa4b78b495bbb47aec36

    This uses a very simple table:

    CREATE TABLE `comics` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
    `title` varchar(50) DEFAULT NULL,
    `description` varchar(150) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;

    Tested and it does work.

    Does this help?

  • anjali jibhakate

    Thank you so much SAM its working….

  • anjali jibhakate

    but the only problem m getting is… The data is not loading on comicDetails page…

  • Glad it’s helped, Anjali.

  • anjali jibhakate

    hello Sam .. Please help me for loading data from database :(

  • Amit Gupta

    Hi Sam,

    Thanks a lot!!!. You resolved my last issue as well that is really tough for the novice app developer like me. Actually I have stopped trying and got busy in some other work. But your reply once again inspires me to move forward in app coding as I need to re-collect everything to run the app and this time it worked perfectly with the code you provided.

    Might be some day I will also code and run like you! You always an inspiration for others. I really appreciate.

    Thanks again, Sam!!!

  • anjali jibhakate

    Hi Sam… Could you please tell me how to create a login form with this comicid

  • A log in form? This has nothing to do with the article. I’m sure there are many articles about log in forms though.

  • Glad it helped, Amit!