I just started with learning Angular and now i'm busy with an web application that shows some records i fetched from a JSON. The JSON looks like:
"results": [
{
"easy": false,
"id": 1,
"title": "title",
}
]
i am parsing that on this way (seems correct to me)
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.thing = data.results;
});
});
So now that i am in this JSON file i need to get the ID (in this case its 1) and with that ID i need to do a new request api.com/game/{id} to get more detailed information about the result from the first file.
What is the best way to do that?
$http.get('api.com/game/' + $scope.thing.id, function(...){ });
Point to note, you do not have to manually parse JSON with angular. It will do that for you. So data.results already has the object representing your response.
i think it is good idea if you do like this:
var app = angular.module("DB", []);
app.controller("Controller", function($scope, $http) {
$http.defaults.headers.common["Accept"] = "application/json";
$http.get('api_url').
success(function(data, status, headers, config) {
$scope.thing = data.results;
$scope.id=data.results[0].id;
gameInfo();
});
});
var gameInfo=function(){
$http.get('api.com/game/'+$scope.id).
success(function(data, status, headers, config) {
$scope.newThing = data;
});
}
Also take a look at ngResource which is a module that gives you more fine-grained control over HTTP requests. It does parameter replacement among other things (custom interceptors, etc.)
https://docs.angularjs.org/api/ngResource/service/$resource
Related
Learning angular and in my app I have a local json file that I can use $http.get to read data from the file, but now I also want to post data to it.
For example my json file looks like this:
{
"name": "old name"
}
And in my controller I am attempting to edit that name:
var data = $.param(
{"name": "new data"}
);
$http.post('testData.json', data)
.success(function (data,status) {
console.log("Post success");
})
.error(function () {
console.log("Post failed");
});
The error "no element found" appears in my browser console when it attempts the http.post. I'm sure it's pointing to the right file and that the json file is actually there.
Any advice?
Dont forget to stringy the JSON!:
angular.module('myApp', [])
.controller('myCtrl', function ($scope, $http) {
$scope.hello = {name: "Boaz"};
$scope.newName = "";
$scope.sendPost = function() {
var data = $.param({
json: JSON.stringify({
name: "new data"
})
});
$http.post("/echo/json/", data).success(function(data, status) {
$scope.hello = data;
})
}
})
You cannot post to a local json file -- it just doesn't work that way. This is what you did in your code; see below.
$http.post('testData.json', data)
.success(function (data,status) {
console.log("Post success");
})
As noted, you posted to a local JSON file which -- as stated, just doesn't work.
You need to post to a local endpoint. See #jdersen's comment on the OP for using a https://postb.in/ to post your data OR set up or a local endpoint and try posting to that.
Working Fiddle
I am using AngularJs 1.5 RC build.
I have a view wherein I am using ng-repeat to iterate over a collection , like so
<tr ng-repeat="user in users">
<td>{{user.JobID}}</td>
<td>{{getManager(user.userID)}}</td>
<td>{{user.StatusDesc}}</td>
<td>{{user.StartedAt}}</td>
</tr>
The idea here is to use the getManager function to get the name of the manager for each and every user in the users collection.
As an aside , I have to use this approach since the API is not returning me all the information.
This is how the getManager function looks like now.
$scope.getManager = function($id) {
return "John Doe";
}
The entire controller looks as follows
var app = angular.module('userapp', ['ui.bootstrap']);
app.controller('MainController', ['$scope','$http', function($scope, $http) {
$scope.getUsers = function() {
$http.get("http://localhost/getUsers").
success(function(data, status, headers, config) {
$scope.users = data.resource;
}).
error(function(data, status, headers, config) {
// log error
console.error("An error as encountered. Error follows:");
console.error(data);
});
}
$scope.getManager= function($id) {
return "John Doe";
}
}]);
So in my page view, I am getting "John Doe" as a manager for all my users.
Problem
The problem begins whenever I try to get the real manager for a user. So if i replace my dummy getManager with the following function
$scope.getManager = function($id) {
$http.get("http://localhost/user/manager/"+$id).
success(function(data, status, headers, config) {
return (data.resource[0].ManagerName);
}).
error(function(data, status, headers, config) {
// log error
console.error("An error as encountered. Error follows:");
console.error(data);
});
}
AngularJs starts complaining and fails with the following
https://docs.angularjs.org/error/$rootScope/infdig?p0=10&p1=%5B%5D
Can you please let me know what might be happening here.
Please note , I am an Angular noob, hence your patience will be well appreciated.
Thanks
You should call ajax in that way inside {{}} interpolation. It will get called on each digest cycle and will throw $rootScope/infdig error.
So I'd suggest you to call the getManager method as soon as you retrieve a data from server. Then after getting data from a server you need to call getManager method just by passing UserId(look I change getManager implementation to return managerName by returning data). After getting managerName you need to bind that manager name to user object & use {{user.ManagerName}} on the HTML.
Markup
<tr ng-repeat="user in users">
<td>{{user.JobID}}</td>
<td>{{user.managerName}}</td>
<td>{{user.StatusDesc}}</td>
<td>{{user.StartedAt}}</td>
</tr>
Code
$scope.getUsers = function() {
$http.get("http://localhost/getUsers")
.success(function(data, status, headers, config) {
$scope.users = data.resource;
angular.forEach($scope.users, function(user){
(function(u){
$scope.getManager(u.UserID).then(function(name){
u.ManagerName = data;
})
})(user);
})
})
};
$scope.getManager = function($id) {
return $http.get("http://localhost/user/manager/"+$id).
then(function(response) {
var data = response.data;
return (data.resource[0].ManagerName);
},function(error) {
console.error("An error as encountered. Error follows:");
});
};
Side Note
Don't use .success & .error function on $http calls as they are
deprecated.
This is a really bad practice. If you have N users, you will send N queries to fetch every data. You should return this data in http://localhost/getUsers response.
You can try:
$scope.getManager = function($id) {
return $http.get("http://localhost/user/manager/"+$id)
...
}
Here is my controller and service:
var app = angular.module('myApp', ['ui.bootstrap']);
app.service("BrandService", ['$http', function($http){
this.reloadlist = function(){
var list;
$http.get('/admin.brands/getJSONDataOfSearch').
success(function(data, status, headers, config) {
list = data;
}).
error(function(data, status, headers, config) {
});
return list;
};
}]);
app.controller('BrandsCtrl', ['$scope','$http','$controller','BrandService', function($scope, $http, $controller, BrandService) {
$scope.brands = BrandService.reloadlist();
angular.extend(this, $controller("BrandCtrl", {$scope: $scope}));
}]);
I searched for this issue and tried answers of questions but I couldn't get solution. I am new at angular so can you explain with details; why I couldn't get the data from service to controller this way ?
The return used for data is for the callback of your function.
You must use the promise returned by $http like this.
In your service return the promise :
return $http.get('/admin.brands/getJSONDataOfSearch').
success(function(data, status, headers, config) {
return data;
}).
error(function(data, status, headers, config) {
});
Use then() on the promise in your controller :
BrandService.reloadlist()
.then(function (data){
$scope.brands = data;
});
It's not angular, it's the Javascript. The function you put in this.reloadlist does not return any value. It has no return at all, so the value returned will be undefined. The success handler does return something, but it will be run long after reloadlist finished working.
Besides what #fdreger already pointed out (missing return value), $http.get(...) is an async method. The return value is a promise not the actual value.
In order to access the value you need to return it from reloadlist like this:
this.reloadList = function() {
return $http.get('/admin.brands/getJSONDataOfSearch');
// you need to handle the promise in here. You could add a error handling here later by catching stuff...
}
and in the controller you can add it to the $scope like this:
BrandService
.reloadlist()
.then(function(res) {
$scope.brands = res.data;
});
The callback passed to then() is called as soon as the HTTP request has successfully completed, this makes the call asynchronous.
Besides the angular documentation for promises the article on MDN is a good read too.
I'm an angular noob and am really frustrated with a particular problem.
I have a $resource returning data from the server, which contains key/value pairs i.e. detail.name, detail.email etc.
I can access this information on the view using {{detail.name}} notation, but I cannot access it in the code, which is driving me nuts, as I need this data to do stuff with.
How can I access it in the backend?
here's the code generating the data:
mydata = Appointment.get({id: $stateParams.id}, function(data){
geocoder.geocode(data);
$scope.detail = data;
});
on the view I have the following:
<address class="text-left">
{{detail.address_1}}</br>
{{detail.city}}</br>
{{detail.postcode}}</br>
</address>
</hr>
<p> {{detail.lat}}</p>
<p> {{detail.lng}}</p>
<p> {{center}}</p>
this is all ok.
however, if I add console.log($scope.detail.lat) in the $resource callback i get undefined.
Here is the resource definition:
angular.module('MyApp')
.factory('Appointment', function($resource){
return $resource('/api/admin/:id', { id: "#_id" }, {
query: {method:'GET', isArray:true},
update: { method:'PUT' }
});
})
and the geocoder factory if anyone is interested:
angular.module('MyApp')
.factory('geocoder', ['$http','$state', function($http, $state){
var geocoder ={};
geocoder.geocode = function (formData){
var myformData = {};
var address = formData.address_1+', '+formData.city+', '+formData.postcode;
var key = 'AIzaSyACVwB4i_6ujTrdjTMI-_tnsDrf6yOfssw';
$http.get('https://maps.googleapis.com/maps/api/geocode/json?address='+address+'&key='+key).
success(function(results, status, headers, config) {
var results = results.results[0];
formData.lat = results.geometry.location.lat;
formData.lng = results.geometry.location.lng;
myformData = formData;
return myformData;
// this callback will be called asynchronously
// when the response is available
}).
error(function(results, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
return geocoder;
}])
Can anyone help?
You could do utilize the promise return from the $resource object & then utilize that promise in controller.
Factory
angular.module('MyApp')
.factory('Appointment', function($resource){
return $resource('/api/admin/:id', { id: "#_id" }, {
query: {method:'GET', isArray:true},
update: { method:'PUT' }
});
})
Controller
mydata = Appointment.get({id: $stateParams.id}).$promise;
mydata.then(function(data){
geocoder.geocode(data);
$scope.detail = data;
});
I'm just getting started with Angular.js and I'm not sure how to "link" two "models" together. I have the following code in my index.php file
<div ng-controller="AccountCtrl">
<h2>Accounts</h2>
<ul>
<li ng-repeat="account in accounts">
<span>{{account.id}} {{account.ownedBy}}</span>
</li>
</ul>
</div>
<div ng-controller="TransactionCtrl">
<h2>Transactions</h2>
<ul>
<li ng-repeat="transaction in transactions">
<span>{{transaction.id}} {{transaction.timestamp}} {{transaction.amount}} {{transaction.description}} {{transaction.account}}</span>
</li>
</ul>
</div>
and the following js
function AccountCtrl($scope, $http) {
// initialize Data
$http({
method:'GET',
url:'http://api.mydomain.ca/accounts'
}).success(function(data, status, headers, config) {
$scope.accounts = data;
}).error(function(data, status, headers, config) {
alert('Error getting accounts. HTTP Response status code: '+status);
});
}
function TransactionCtrl($scope, $http) {
// initialize Data
$http({
method:'GET',
url:'http://api.mydomain.ca/transactions'
}).success(function(data, status, headers, config) {
$scope.transactions = data;
}).error(function(data, status, headers, config) {
alert('Error getting transactions. HTTP Response status code: '+status);
});
}
So in my example each account will have many transactions and I want to add a function to my account controller to calculate the balance of the account based on the transactions but I'm not sure how to do that because they are in different $scopes.
Is there a way to do this in Angular or do I have to return the "linked" transaction information in my JSON response from the server when I get the accounts?
I guess account holds transactions, right?
Then I guess, you can create an service to manage account / transaction data.
Inject this service into both controllers.
module = angular.module('app', []);
module.factory('accountService', function($http) {
var obj = {
// handles http communication to/from server.
// also has methods/getters/setters for data manipulation, etc.
};
return obj;
});
module.controller('AccountCtrl', function($scope, accountService) {
// access accountService for the view-databind.
});
module.controller('TransactionCtrl', function($scope, accountService) {
// access accountService for the view-databind.
});
Since you are making both http requests at the same time, I would change my service to return the transactions as a property of the account object. Then it would be one server call, less overhead, and you data would be in the format that you need it in. I think you have the right idea with your last question.
And good choice using Angular. If you haven't found them yet, John Lindquest released a great set of videos at egghead.io.