I'd like to get a couple of values out of a JSON file in my app controller.
I have a JSON file that looks something like this:
{
"login": [
{
"username": "admin",
"password": "admin"
}
],
"header": [
{
"subTitle": "Hello",
"color": "red"
}
]
}
I am attempting to retrieve a value like this:
app.controller('loginCtrl', function($http, $scope) {
data = $http.get('data.json');
console.log(data.login.username);
}
However, all I'm getting in the console is TypeError: Cannot read property 'username' of undefined.
data = $http.get('data.json');
data.then(function(result){
console.log(result.login[0].username);
});
Even though your javascript is synchronous,the call you make is always asynch
$http.get('data.json').then(function (response) {
console.log(response.data)
});
So in your terms javascript called the get function and before it returned with result it executed this console.log(data.login.username);
So you did not got the expected result
Related
In my understanding, $scope.categories is already defined. Then why am I getting this error and not able to access data from the Json file?
Here is my controller:
(function(){
app.controller('productsCtrl', ['$scope','$cookies', '$http', function($scope,$cookies,$http){
$http.get("controllers/data.json").then(function (response) {
$scope.categories = response.data;
});
$scope.specials = [categories[0].laptops[1], categories[1].accessories[0]];
}]);
})();
Here is my Json file:
[
{
"laptops": [
{
"name": "Asus Laptop",
"price": 300
},
{
"name": "HP Notebook",
"price": 200
}
]
},
{
"accessories": [
{
"name": "WD Hard Drive",
"price": 100
},
{
"name": "WD Blue SSD",
"price": 700
}
]
}
]
You have assigned response data into $scope.categories, you need to use $scope.categories instead of categories and also you should add into $scope.specials once http call completed like
(function(){
app.controller('productsCtrl', ['$scope','$cookies', '$http', function($scope,$cookies,$http){
$scope.specials = [];
$http.get("controllers/data.json").then(function (response) {
$scope.categories = response.data;
$scope.specials.push($scope.categories[0].laptops[1]);
$scope.specials.push($scope.categories[1]. accessories[0]);
});
}]);
})();
There's actually a few issues here. First is you never define a variable named categories, you have a property of the $scope object named that, so you need to access $scope.categories or the response.data setting it directly.
Second, you have a race condition issue. You are trying to access the values of categories outside the promise, meaning potentially before the get request has returned any data. When you use get().then() like you are, the code after the request doesn't wait for the request to finish before it runs, so whatever is faster runs first. Because one of the two operations running is accessing an external endpoint and the other is local javascript code, the flow is almost guaranteed to be this:
send get request to "controllers/data.json"
set $scope.specials - causing your undefined error
set $scope.categories when get request promise resolves
You need to access the categories inside the promise to guarantee that it actually has been defined at the point you are trying to access it:
$http.get("controllers/data.json").then(function (response) {
$scope.categories = response.data;
$scope.specials = [$scope.categories[0].laptops[1], $scope.categories[1].accessories[0]];
});
It's also generally a bad idea to hard code indexes like this, if the data changes you run into a possible index out of bounds error.
I have problem with geting a data from Restangular promise. I always get a promise instead of pure data in JSON.
This is response from my API
localhost:3000/api/meal
{
"status": "success",
"data": [
{
"meal_id": 4,
"meal_type_id": 2,
"description": "blahblah",
"price": "3.50",
"info": "120/120/20g",
"restaurant_id": 2
},
...
...
}
],
"message": "Retrieved ALL meals"
}
This is my config method for extracting data from response
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var extractedData;
// .. to look for getList operations
if (operation === 'getList') {
// .. and handle the data and meta data
return data.data;
} else {
extractedData = data.data;
}
return extractedData;
});
This is how I am trying to get data from my API
Restangular.all('meal').getList().then(function(meals) {
$scope.menu = meals; //meals.plain()
console.log($scope.menu);
});
but i always get this response
I need just JSON array from "data" field for using in my application.
Sry guys, after hours of research and debuging I found bug in my backend API in one specific select. Now Express.js, pg-promise and application works correctly.
Let's say I have a animals.json file with the following content:
{
"animals": {
"elephant": {
"size": "large"
},
"mouse": {
"size": "small"
}
}
}
And I'm adding that data to the scope of my controller:
animalsApp.controller('animalsCtrl', function($scope, $http){
$http.get('../../animals.json').success(function(data){
$scope.animals = data.animals;
});
});
Which works perfectly, however let's say I need to get some data from an API that I need to add to $scope.animals, which has the following data:
{
"animal_name": "Leonardo"
}
Which is returned when I go to the api with the jsons data:
http://api.someapi.com/animals/{animals.elepahant} // returns above json
Pretend {animals.elaphant} is the results I get when i loop my json, get a value from it, and get the data from a remote api with the query being a variable of mines, add results to my json and return that new modified json in $scope.animals.
So the final json would look like:
{
"animals": {
"elephant": {
"size": "large",
"name": "Leonardo"
},
"mouse": {
"size": "small",
"name": "Vader"
}
}
}
How can I achieve this?
Normally you would have an array of animals and loop through that array.
Since you have an object the principle is the same. It is important to use a closure for the loop. Will use angular.forEach() to create that closure.
Using for loops by themselves do not create a closure and can be problematic since the loop finishes long before the request responses are returned
$http.get('../../animals.json').success(function(data){
$scope.animals = data.animals;
angular.forEach(data.animals, function(v, animal_type){
var url = 'http://api.someapi.com/animals/' + animal_type;
$http.get(url).success(function(resp){
v.name = resp.animal_name;
});
});
});
There are also alternative ways to write this using chained promises.
I kept it simple for now
I am trying to create a user's feed on my page using Facebook JS SDK but I am having issues accessing the values of nested objects.
This is my code:
FB.api('/me/feed', function(response) {
alert(response.data);
});
The alert here will return [object Object]
The data object is this:
{
"data": [
{
"message": "Some message",
"id": "some ID",
"created_time": "2014-01-05T22:46:10+0000"
}
],
"paging": {
"previous": "Link",
"next": "Link"
}
}
I need to access the message part of the object but I don't know how.
Simply access the properties directly
FB.api('/me/feed', function(response) {
alert(response.data.message);
});
I had to use JSON after all
FB.api('/me/feed',{limit:10}, function(response){
var jsonText = JSON.stringify(response.data,["picture"]);
alert(jsonText);
});
This will return an array with all the values of 'picture'
This is the example output
[{"picture":"https://fbcdn-photos-d-a.akamaihd.net"},
{"picture":"https://fbcdn-photos-g-a.akamaihd.net"},
{"picture":"https://fbexternal-a.akamaihd.net"},{},
{"picture":"https://fbcdn-profile-a.akamaihd.net"}]
It looks likedata is an array with a single element, so to get message, you will want to use response.data[0].message
I have a AngularJS-based frontend using restangular to fetch records from a Django backend I've built.
I'm making a call for a client list with the following:
var app;
app = angular.module("myApp", ["restangular"]).config(function(RestangularProvider) {
RestangularProvider.setBaseUrl("http://172.16.91.149:8000/client/v1");
RestangularProvider.setResponseExtractor(function(response, operation) {
return response.objects;
});
return RestangularProvider.setRequestSuffix("/?callback=abc123");
});
angular.module("myApp").controller("MainCtrl", function($scope, Restangular) {
return $scope.client = Restangular.all("client").getList();
});
Chrome is showing the backend returning data with an HTTP 200:
abc123({
"meta": {
"limit": 20,
"next": "/client/v1/client/?callback=abc123&limit=20&offset=20",
"offset": 0,
"previous": null,
"total_count": 2
},
"objects": [{
"id": 1,
"name": "Test",
"resource_uri": "/client/v1/client/1/"
}, {
"id": 2,
"name": "Test 2",
"resource_uri": "/client/v1/client/2/"
}]
})
But once that happens I'm seeing the following stack trace appear in Chrome's console:
TypeError: Cannot set property 'route' of undefined
at restangularizeBase (http://172.16.91.149:9000/components/restangular/src/restangular.js:395:56)
at restangularizeCollection (http://172.16.91.149:9000/components/restangular/src/restangular.js:499:35)
at http://172.16.91.149:9000/components/restangular/src/restangular.js:556:44
at wrappedCallback (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:6846:59)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:6883:26
at Object.Scope.$eval (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:8057:28)
at Object.Scope.$digest (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:7922:25)
at Object.Scope.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:8143:24)
at done (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:9170:20)
at completeRequest (http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.js:9333:7) angular.js:5754
I did a breakpoint on line 395 in in restangular.js:
L394 function restangularizeBase(parent, elem, route) {
L395 elem[config.restangularFields.route] = route;
The first time it hits the breakpoint elem is just an object and route has the value of client.
The second time the breakpoint is hit elem is undefined and route has the value of client.
Any ideas why elem would be undefined the second time around?
When requesting lists, Restangular expects the data from the server to be a simple array. However, if the resulting data is wrapped with result metadata, such as pagination info, it falls apart.
If you are using Django REST Framework, it will return results wrapped like this:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"name": "Foo"
},
{
"id": 2,
"name": "Bar"
}
]
}
To translate this, you need to create a response extractor function. It's easiest to specify in the module config:
angular.module('myApp', ['myApp.controllers', 'restangular']).
config(function(RestangularProvider) {
RestangularProvider.setBaseUrl("/api");
// This function is used to map the JSON data to something Restangular
// expects
RestangularProvider.setResponseExtractor(function(response, operation, what, url) {
if (operation === "getList") {
// Use results as the return type, and save the result metadata
// in _resultmeta
var newResponse = response.results;
newResponse._resultmeta = {
"count": response.count,
"next": response.next,
"previous": response.previous
};
return newResponse;
}
return response;
});
});
This rearranges the results to be a simple array, with an additional property of _resultmeta, containing the metadata. Restangular will do it's thing with the array, and it's objects, and you can access the _resultmeta property when handling the array as you would expect.
I'm the creator of Restangular.
The restangularizeBase function is called first for your collection and then for each of your elements.
From the StackTrace, the element is OK, but once the collection is sent to restangularizeBase, it's actually undefined. Could you please console.log response.objects? Also, please update to the latest version.
Also, for the default request parameter, you should be using defaultRequestParams instead of the requestSuffix. requestSuffix should only be used for the ending "/"
Let me know if I can help you some more!