Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access HTTP GET JSON property in angular controller

I am using a factory in angular.js and $http.get method to grab and process JSON data. The JSON data seems successfully parsed into factory, but I have problem access property of this JSON data.

Here is my js code:

var app = angular.module("app", []);      

app.factory('mainInfo', function($http) { 

    var obj = {content:null};
    //the php will return json data below
    $http.get('http://localhost/test.php').success(function(response){ 
        obj.content = response.records;

    });    

    return obj;    
});


app.controller('Ctrl', function($scope, mainInfo){
    $scope.foo = mainInfo.content;
}) ;

Now if I try to access foo within Ctrl controller, the webpage will display no data:
<div ng-controller="Ctrl">Controller: {{foo}}</div>
However, if I change to $scope.foo = mainInfo in the Ctrl, then the webpage will display correctly the JSON data.

May I know what is the proper way to access mainInfo.content property in Ctrl controller?

The reason why I need to access JSON property is because I need to pre-process the data. I intend to use these data in a Chart, as in below controller. Currently this controller is not working either, because I have the same problem accessing JSON property as in the Ctrl controller.

app.controller("LineCtrl", function ($scope, mainInfo) {
    var timePoints = [];
    var percentagePoints = [];
    var i = 0;
    for( i = 0; i < mainInfo.content.length; i ++) {
        timePoints.push(mainInfo.content[i].Time);
        percentagePoints.push(mainInfo.content[i].Percentage);
    }

    $scope.labels = timePoints;

    $scope.data = percentagePoints;

    $scope.onClick = function (points, evt) {
        console.log(points, evt);
    };
});

The json data:

{
"records": [
    {
        "Id": "1",
        "Time": "2015-07-25 08:00:00",
        "Percentage": "60"
    },
    {
        "Id": "2",
        "Time": "2015-07-25 09:00:00",
        "Percentage": "70"
    },
    {
        "Id": "3",
        "Time": "2015-07-25 10:00:00",
        "Percentage": "80"
    }
    ]
}

With regards to the factory-controller communication, I am just referring the solution from another post: reference

like image 310
modeller Avatar asked Jul 30 '15 03:07

modeller


2 Answers

$http.get returns a promise -- your problem is that you are returning "obj" immediately, and your controller tries to access the data before the $http.get promise is resolved.

use $http like so (no need to use $q.defer() as shown in the other comment):

var app = angular.module("app", []);      

app.factory('mainInfo', function($http) { 
    var getRecordsPromise = $http.get('http://localhost/test.php').then(function(response){ 
        //whatever is returned here will be accessible in the .then that is chained
        return response.data.records;
    });    

    return {
        getRecords: getRecordsPromise
    };    
});


app.controller('Ctrl', function($scope, mainInfo){
    mainInfo.getRecords.then(function (records) {
        $scope.foo = records;
    });
}) ;
like image 117
William B Avatar answered Oct 14 '22 10:10

William B


Try this instead

var obj = {content: []};
obj.$promise = $http.get('http://localhost/test.php').then(function(response) {
    angular.copy(response.data.records, obj.content);
    return response.data;
});
return obj;

The reason your former method didn't work was because you were re-assigning the content property of obj, thus destroying any previous references.

This is also why using $scope.foo = mainInfo worked because the reference to obj (via mainInfo) was maintained.

Using angular.copy maintains the previous reference whilst populating the data.


That should take care of references in the template that get updated when the $http promise resolves (due to $http triggering a digest cycle). For accessing the data in your controller, use the $promise property

$scope.foo = mainInfo.content;
mainInfo.$promise.then(function(data) {
    // access data.records here
});

Maintaining the data inside your factory is a good idea if you share your factory with multiple consumers (eg controllers). They may all reference mainInfo.content and mainInfo.$promise and all will be accessing the same data set.

like image 29
Phil Avatar answered Oct 14 '22 10:10

Phil