I have two json files being requested for two differents angularjs services.
/people.json
{user-name, user-id}
/task.json
{name-task, task-id, responsible-id}
Where responsible-id = user-id.
I can pass an ID parameter to the task json to request all the task for the user with that ID: /task.json?ID=12
I'm trying to create a nested ng-repeat, the first one to get all the users in /people.json, the second to get all the task for each user in the loop but i ended up with something like this: http://i.imgur.com/xgG0K7i.png
The first ng-repeat shows correctly the different users, but the second show the same tasks of the first user to the others users in the list.
¿How can i change the parameter to update correctly for the nested ng-repeat?
My Services:
.service('TeamworkPeopleSrvc', function($http, $q){
var deferred = $q.defer();
var TeamworkPeopleSrvc = this;
TeamworkPeopleSrvc.getPeople = function(){
$http.defaults.headers.common['Authorization'] = 'Basic ' + window.btoa('mycustomapikey' + ':' + 'X');
$http({
method: 'GET',
url: 'http://projects.com/people.json',
params: { 'pageSize':'5'},
})
.then(function(response) {
deferred.resolve(response);
});
return deferred.promise;
};
return TeamworkPeopleSrvc;
})
.service('TeamworkTasksSrvc', function($http, $q){
var deferred = $q.defer();
var TeamworkTasksSrvc = this;
TeamworkTasksSrvc.getTasks = function(id){
$http.defaults.headers.common['Authorization'] = 'Basic ' + window.btoa('mycustomapikey' + ':' + 'X');
$http({
method: 'GET',
url: 'http://projects.com/tasks.json' ,
params: { 'id':id, 'getSubTasks':'no', 'pageSize':'10'},
})
.then(function(response) {
deferred.resolve(response);
});
return deferred.promise;
};
return TeamworkTasksSrvc;
})
My Controller
.controller('PeopleCtrl', function ($scope, TeamworkPeopleSrvc, TeamworkTasksSrvc) {
$scope.init = function(){
$scope.peopleObjects();
};
$scope.taskObjects = function(id){
TeamworkTasksSrvc.getTasks(id)
.then(function(response){
$scope.userTasklist = response.data['todo-items'];
});
};
$scope.peopleObjects = function(){
TeamworkPeopleSrvc.getPeople()
.then(function(response){
$scope.userlist = response.data.people;
});
};
$scope.init();
});
and try to init the tasks with the updated user id in the template
<div ng-controller="PeopleCtrl">
<div ng-repeat="person in userlist">
<h3>{{person['id']}} | {{person['first-name']}} {{person['last-name']}}</h3>
<div ng-init="taskObjects(person['id'])">
<div ng-repeat="task in userTasklist">
{{task['responsible-party-id']}} - {{task['content']}}
</div>
</div>
</div>
</div>
Best Regards.
The problem is in your controller code. You are using the same $scope for both loops, which means that each time you call taskObjects(), you are overwritting $scope.userTasklist with a new task list. You should either establish a new scope for each instance within the loop, or you should make $scope.userTasklist an object with properties matching the person.id.
In your controller change:
$scope.taskObjects = function(id){
TeamworkTasksSrvc.getTasks(id)
.then(function(response){
if(!$scope.userTasklist) {
$scope.userTasklist = {};
}
$scope.userTasklist[id] = response.data['todo-items'];
});
};
And then in your view use:
<div ng-controller="PeopleCtrl">
<div ng-repeat="person in userlist">
<h3>{{person['id']}} | {{person['first-name']}} {{person['last-name']}}</h3>
<div ng-init="taskObjects(person['id'])">
<div ng-repeat="task in userTasklist['id']">
{{task['responsible-party-id']}} - {{task['content']}}
</div>
</div>
</div>
</div>
Defective $q.defer Anti-Pattern1
.service('TeamworkPeopleSrvc', function($http, $q){
var deferred = $q.defer();
var TeamworkPeopleSrvc = this;
TeamworkPeopleSrvc.getPeople = function(){
$http.defaults.headers.common['Authorization'] = 'Basic ' + window.btoa('mycustomapikey' + ':' + 'X');
$http({
method: 'GET',
url: 'http://projects.com/people.json',
params: { 'pageSize':'5'},
})
.then(function(response) {
deferred.resolve(response);
});
return deferred.promise;
};
return TeamworkPeopleSrvc;
})
Both services in the code use a defective $q.defer Anti-Pattern. With the deferred object created outside the .getPeople function, the promise will only be resolved once with the first resolve. Subsequent resolves are ignored and the promise always returns the first value. In addition if the XHR has an error, the error information is lost. With errors, the promise never resolves or resolves only with the first fulfilled XHR.
Implemented Without $q.defer
.service('TeamworkPeopleSrvc', function($http, $q){
var TeamworkPeopleSrvc = this;
TeamworkPeopleSrvc.getPeople = function(){
var authHeader = { Authorization: 'Basic ' +
window.btoa('mycustomapikey' + ':' + 'X')
};
var httpPromise = ($http({
method: 'GET',
url: 'http://projects.com/people.json',
headers: authHeader,
params: { 'pageSize':'5'},
})
);
return httpPromise;
};
return TeamworkPeopleSrvc;
});
To implement the service correctly, simply return the promise returned by the $http service. A new promise will be created each time the $http function is invoked and error information will be properly retained.
Related
When i go to list.html right after loading the page it doesnt show me the list. I need to go to form.html first and then back to list.html and then it gives me the list. When i had $http functions in controller it worked as i wanted but now that they are in service they dont work like before.
app.js
app.service("dataservice", function($http){
var list = [{}];
this.get = function(){
$http.get("harjoitus22/backend.php").success(function(response){
list = response;
});
};
this.save = function(newcontact){
$http({
method: 'post',
url: 'harjoitus22/backend.php',
data: newcontact,
header: 'Access-Control-Allow-Origin: *'
}).success(function(response){
list = response;
});
};
this.give = function(){
return list;
};
});
app.controller("mainController", function($scope, $location, dataservice){
$scope.save = function(){
dataservice.save($scope.newcontact);
$scope.newcontact = {};
$location.path("/list");
$scope.list = dataservice.give();
};
$scope.get = function(){
dataservice.get();
$scope.list = dataservice.give();
};
});
list.html
<tbody ng-init="get()">
<tr ng-repeat="object in list">
<td>{{object.nimi}}</td>
<td>{{object.email}}</td>
<td>{{object.ruoka}}</td>
<td>{{object.sauna}}</td>
</tr>
</tbody>
$http call works asynchronously, when you call it, It will not give you response on next line execution. To keep eye on that ajax you should take use of promise return by $http method.
For achieving the same you need to return promise object from the service get method ($http methods does return's promise object, which helps you to execute your code by putting up in its .then function's).
Service
this.get = function(){
return $http.get("harjoitus22/backend.php").then(function(res){
list = res.data;
});
};
Controller
dataservice.get().then(function(){
$scope.list = dataservice.give();
});
I've got a employeeController and a employeeFactory in the employeeFactory I receive an employee like this:
function employeeFactory(authenticationFactory,requestFactory,GLOBALS) {
var factory = {};
var vm = this;
vm.employee = {};
factory.getEmployee = function(id) {
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
requestFactory.post(url, data)
.then(function (response) {
return vm.employee = response.data.result.Employee;
}, function () {
$window.location.assign('/');
});
}
return factory;
}
In my controller I'm trying to receive it like this:
console.log(employeeFactory.getEmployee($routeParams.id));
But the result is null?
When I console.log the response in my requestFactory I receive an employee object. What am I doing wrong?
Reason behind it is, you missed to return promise of requestFactory.post from factory.getEmployee method
Code
factory.getEmployee = function(id) {
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
return requestFactory.post(url, data)
.then(function (response) {
return vm.employee = response.data.result.Employee;
}, function () {
$window.location.assign('/');
});
}
But even though you do it, you will not able to get value employee object printed. It will print promise object return by $http.post method/ $resource method
For getting hold on that object you need to use .then function over that promise object. like below
employeeFactory.getEmployee($routeParams.id).then(function(employee){
console.log('Employee', employee)
})
We can use deferred api in angularjs for better communication between caller and service.
factory.getEmployee = function(id) {
var deferred = $q.defer();
data = {"api_token": authenticationFactory.getToken()};
url = GLOBALS.url + 'show/employee/' + id;
return requestFactory.post(url, data)
.then(function (response) {
deferred.resolve(response.data.result.Employee);
}, function () {
deferred.reject();
});
return deferred.promise;
}
On your controller:
employeeFactory.getEmployee($routeParams.id).then(function(employee){
console.log('Employee', employee)
},function(){
$window.location.assign('/');
})
By this approach we can notify caller with some messages if your response gets delayed.
For more info see this link.
angular promises
It is my first try writing up a service in AngularJS. I have a service, in which I have a function. When I call this service from my controller, it says XXXService.XXXfunction is not a function.
My Javascript is like,
var sharecycle0_angularfire = angular.module("sharecycle0_angularfire", []);
sharecycle0_angularfire.service("baseHttp", function($http, $q){
self.getFire = function(){
var deferred = $q.defer();
$http({
method: GET,
url: "https://boiling-inferno-1234.firebaseio.com/Cat"
}).then(function(response){
deferred.resolve(response);
},function(response){
deferred.reject(resposne);
});
return deferred.promise;
};
});
sharecycle0_angularfire.controller("angularfirecontroller", function($scope, baseHttp, $window){
$scope.fireClick = function(){
baseHttp.getFire()
.then(
function(response)
{
$("<div/>").text(response).appendTo($("#successData"));
},
function(response)
{
$window.alert("error: "+response);
}
);
};
});
My HTML is like,
<body ng-controller="angularfirecontroller">
<button id="fireClickButton" ng-click="fireClick()">fireClick</button>
<div id="successData"/>
</body>
I expect the service code to run upon my button being hit.
You have some issues here, you are not attaching the function getFire to the service instance, instead you are attaching it to the global variable self. self global variable is generally an alias to window object in many browsers so you are attaching the function to the window and not to the controller instance. Since http already returns a promise you do not need to create a deferred object there, instead just return the result of $http. Apart from that GET needs to be a string value, you are trying to use an undefined variable GET and not "GET". Many a times placing a debug log in relevant areas of the code will help you diagnose the issue.
All you would need is:
sharecycle0_angularfire.service("baseHttp", function($http, $q){
this.getFire = function(){
return $http({
method: 'GET',
url: "https://boiling-inferno-1234.firebaseio.com/Cat"
});
}
});
if you intended to cache this then you should create a local variable and assign this to that.
i.e
sharecycle0_angularfire.service("baseHttp", function($http, $q){
var _this = this; //Or var self = this
_this.getFire = function(){
return $http({
method: 'GET',
url: "https://boiling-inferno-1234.firebaseio.com/Cat"
});
}
});
I'm trying to get data from a server in my AngularJS app, using $http.get. But when I execute the request, it seems to get cancelled by something. It happens with every link I use. Local files are working.
Below the code from Controller.js:
angular
.module('schoolApp')
.controller('configController', [
'apiService', '$http', function (apiService, $http) {
var vm = this;
vm.isActive = isActive;
vm.addPortal = addPortal;
...
function addPortal() {
...
apiService.getServerData('someUrl', "1.0")
.then(function (result) {
var test = result.data;
})
.catch(function (result) {
console.log(result);
});
}
...
And the Service.js:
angular
.module('schoolApp')
.service('apiService', [ '$http', function ($http) {
var service = {
getServerData: getServerData,
};
return service;
function getServerData(portalUrl, appVersion) {
// var url = "http://../.../.svc/GetSetting?alias=...&AppVersion=1.0";
var url = "http://xml.buienradar.nl";
//var url = "test.json";
//var url = "xml.xml";
// "http://" +
// portalUrl +
// "/.../.../.svc/GetSetting?alias=" +
// portalUrl +
// "&AppVersion=" +
// appVersion;
return $http.get(url);
}
}]);
Executing this code will show the alert("ERROR: " + result) from the controller class. Data from the result:
result: Object config: Object data: null headers: (c)
status: -1 statusText: ""
__proto __: Object
Network in browser shows the call is cancelled:
http://i.stack.imgur.com/MJoZM.png
More info:
- I'm using Phonegap (tested without and doesn't work either)
- AngularJS 1.4
Ok, found the answer. I called window.location.reload() in the same function, and that conflicted. So, now I added it to the .then() function in the request.
I have an Angular app, and in the controller I need to call a function which makes two http get requests, and I need this function to return these values just when they are resolved. I cannot make them in the $routeProvider resolve because this function needs a value obtained in the same controller.
I show part of the controller:
function myController(info) {
var vm = this;
vm.name = info.data.name;
vm.extra_data = MyService.getExtras(name);
}
And here is part of the code of the service:
function myService($http, $q, API_EVENT1, API_EVENT2) {
return {
getExtras: getExtras
}
function getExtras(name) {
var request1 = API_EVENT1 + '/' + name;
var request2 = API_EVENT2 + '/' + name;
}
}
The function is not complete due to I have tried several methods, but I wasn't successful at all.
My problem is how to return (in getExtras function) both of the results of the requests. I have tried using $q.defer, $q.all and promises, but I'm not able to achieve it.
Using $q.all, for example, I got to retrieve the result, but when I call the function, the object extra_data is undefined, due to the requests have been executed asynchronously.
Thank you in advance for your responses.
I would use $q.all to return combined promise from Service, and process result in controller. e.g.:
function myService($http, $q, API_EVENT1, API_EVENT2) {
return {
getExtras: getExtras
}
function getExtras(name) {
return $q.all([
$http({method: 'GET', url: API_EVENT1 + '/' + name}),
$http({method: 'GET', url: API_EVENT2 + '/' + name})])
);
}
}
function myController(info) {
var vm = this;
vm.name = info.data.name;
MyService.getExtras(name).then(function(data) {
vm.extra_data.first = data[0];
vm.extra_data.second = data[1];
});
}