Why Angularjs continuously call method when send a get request? - javascript

I am new in angularjs. I am try to send a get request to my Web-Api 2 project. But I don't understand why its continuously call my method. I am following AngularJs $http for this.
Here is my error:
My Code is :
<script src="~/Scripts/jquery-2.1.0.js"></script>
<script src="~/Scripts/angular.min.js"></script>
<script>
function loginCtrl($scope, $http) {
$scope.name = function () {
console.log("Add Call");
$http({ method: 'GET', url: 'http://localhost:15229/api/values' }).
success(function (data, status, headers, config) {
console.log(data);
}).
error(function (data, status, headers, config) {
console.log(data);
});
};
}
</script>
<div lang="en" ng-app="" ng-controller="loginCtrl">
{{name()}}
</div>

You don't give enough context information for me to be sure of what you want to achieve. Especially I don't know what returns your api. So I will assume It returns the value you want to display. Your code should look more like this:
function loginCtrl($scope, $http) {
$scope.init = function () {
console.log("Add Call");
$http({ method: 'GET', url: 'http://localhost:15229/api/values' }).
success(function (data, status, headers, config) {
console.log(data);
$scope.name = data;
}).
error(function (data, status, headers, config) {
console.log(data);
});
};
}
<div lang="en" ng-app="" ng-controller="loginCtrl" ng-init="init()">
{{name}}
</div>
You should affect $scope.name in the success callback.
name should be a variable, not a function.
And the ng-init attributes defines the method to be invoked when instanciating the controller. In this case it will invoke the init() method of your controller.

Related

Call function inside ng-repeat to retrieve value

I'm having this situation I'm iterating over a json response from an endpoint:
chunk of controller code:
$http({
method: 'GET',
url: 'http://mywebsite.com/api/v1/stores/'
}).
success(function(data, status, headers, config) {
$scope.stores = data;
}).
error(function(data, status, headers, config) {
$scope.name = 'Error!';
});
and on my html view side I've got this:
<tbody>
<tr ng-repeat="store in stores">
<td>{{store.name}}</td>
<td> {{store.type}} </td>
<td><span ng-repeat="client in retrieveClientName(store.client_id)">
{{client.name}}
</span>
</td>
<td>{{store.address}}</td>
</tr>
</tbody>
As you can see I'm trying to retrieve the client name using a function that receives an store.client_id from the values inside the stores array. Normally using a function triggered by a ng-click will be easy but how can I achieve this "on the fly" while I'm iterating?.
Because executing this I get a kind of infinite loop that breaks all apart.
here is the code of the function that returns client name on the controller side:
$scope.retrieveClientName = function(id) {
$http({
method: 'GET',
url: 'http://mywebsite.com/api/v1/clients?client_id='+id
}).
success(function(data, status, headers, config) {
return $scope.clients=data;
}).
error(function(data, status, headers, config) {
$scope.name = 'Error!';
});
}
I have also try using mg-init directive
<td ng-init="clients=retrieveClientName(store.client_id)"><span ng-repeat="client in clients">{{client.name}}</span></td>
One way would be get all data when you get the stores back
$http({
method: 'GET',
url: 'http://mywebsite.com/api/v1/stores/'
}).
success(function(data, status, headers, config) {
$scope.stores = data;
angular.forEach($scope.stores, function(store){
$scope.retrieveClientName(store.client_id).then(function(clients){
store.clients = clients;
});
});
}).
error(function(data, status, headers, config) {
$scope.name = 'Error!';
});
Edit: I would change the structure a bit for cleaner code
$scope.retrieveClientName = function(store) { // pass in store so we can attach results here
$http({
method: 'GET',
url: 'http://mywebsite.com/api/v1/clients?client_id='+store.client_id
}).
success(function(data, status, headers, config) {
return store.clients = data; // attach result in object
}).
error(function(data, status, headers, config) {
$scope.name = 'Error!';
});
}
$http({
method: 'GET',
url: 'http://mywebsite.com/api/v1/stores/'
}).
success(function(data, status, headers, config) {
$scope.stores = data;
angular.forEach($scope.stores, function(store){
$scope.retrieveClientName(store); // no need .then here
});
}).
error(function(data, status, headers, config) {
$scope.name = 'Error!';
});
<tbody>
<tr ng-repeat="store in stores">
<td>{{store.name}}</td>
<td> {{store.type}} </td>
<td><span ng-repeat="client in store.clients"> <!-- use data here -->
{{client.name}}
</span>
</td>
<td>{{store.address}}</td>
</tr>
</tbody
You must understand that $http jest asynchronous, so Your response will be back after all ng-repeat, so such thing must be done in controller in $q.all and after that render view with ng-repeat.
So do foreach on stores and in foreach add to array, next use this array in $q.all, after $q.all render view.
The retrieveClientName function is wrong: the $http return a promise, the return value of success callback is not the return value of the function and you can't bind the ng-repeat to a promise, try this one:
$scope.retrieveClientName = function(id) {
return $resource('http://mywebsite.com/api/v1/clients?client_id='+id).query();
}
Don't forget to include the ngResource dependency.

AngularJS - Dealing with properties file

I'm trying to read a properties file in angular, It's neccesary to have this file at the root of my project without any kind of angular stuffs, just a simple file, like java.
This is what I'm doing.
Creating a angular.properties file.
angular.properties
{
"url": "http://localhost"
}
This is my controller where I invoke my service method:
controller
captchaService
.all()
.then(function(data) {
...
}, function (data) {
...
});
This is my service class:
service
'use strict';
angular.module('app.service', [])
.factory('myService',
['$http', '$q',
function ($http, $q) {
var _URL = "";
function getValuesFromProperties() {
$http({
method : 'GET',
url : 'angular.properties'
}).success(function (data, status, headers, config) {
_URL = data.url;
}).error(function (data, status, headers, config) {
...
});
}
function all() {
getValuesFromProperties();
var deferred = $q.defer(),
promise = deferred.promise;
sessionStorage.removeItem('X_CAPTCHA_TOKEN');
$http({
method : 'POST',
url : _URL
}).success(function (data, status, headers, config) {
...
}).error(function (data, status, headers, config) {
...
});
return promise;
}
return {
all : all,
getValuesFromProperties : getValuesFromProperties
};
}]);
But here in my services class I have two $http running on an asynchronous way for that reason I can not get the value of url everything else works perfect. How can resolve this? Maybe there is another way to do this. I don't want to create a constant class because this file it's placed at the root of the project and it will be configure for others, they don't need to enter inside a lot of folders and check the code, search and edit. Any idea?

ngResource query returns strange objects

I am new to AngularJS and wanted to try out the $resource functionality.
I have this code:
.factory('GetTasksService', function($resource, BASE_URL) {
return $resource(BASE_URL + 'api/tasks');
})
.controller('TasksCtrl', function ($scope, $http, BASE_URL, GetTasksService) {
$scope.tasks = GetTasksService.query();
$scope.getTasks = function () {
$http({ url: BASE_URL + 'api/tasks', method: 'GET' })
.success(function (data, status, headers, config) {
$scope.tasks = data;
})
.error(function (data, status, headers, config) {
alert("call did not work");
});
}
});
The getTasks function works as expected - returning an array of:["taska", "taskb"] as it should.
The GetTasksService.query() however returns an array of [{"0":"t","1":"a","2":"s","3":"k","4":"a"}, {"0":"t","1":"a","2":"s","3":"k","4":"b"}]
Can anyone tell me what I am doing wrong?
There is an option when specifying an action for an ngResource called isArray;
The default action query sets this as true by default, so you need to set set the action like:
query : {
method : 'GET',
isArray : false
}

AngularJs $scope doesn't update after a GET request on a factory

I have been trying AngularJS for a experimental project and I came along with this problem.
In my html I want to display a list of items
Index.html
<h1>Some list</h1>
<div ng-controller="datlist">
<div ng-repeat="item in items">
<div>Item description: {{item.description}}</div>
<div>Item name: {{item.name}}</div>
</div>
</div>
At first I was using a simple controller to get the information and update the view just using this:
controllers.js (original)
function datlist($scope,$http){
$http({method: 'GET', url: 'http://localhost:61686/getdatlist?format=json', headers: {'Access-Control-Allow-Origin': 'localhost:*'}}).
success(function(data, status, headers, config) {
$scope.items=data.itemsToReturn;
console.log(data);
}).
error(function(data, status, headers, config) {
console.log("fail");
});
}
This was working pretty well and I could get the list of items. Whilst, by changing my structure to use a factory to make the same request and bind it to $scope.items it doesn't work. I tried a lot of variations of $watch but I couldn't get it to update $scope.items. I found something about $apply but I really can't understand how to use it.
controllers.js (new one)
var datModule = angular.module('datModule',[]);
datModule.controller('datlist', function ($scope, datfactory){
$scope.items = datfactory.getlist();
$scope.$watch($scope.items, $scope.items = datfactory.getlist());
});
datModule.factory('datfactory', function ($http){
var factory = {};
factory.getlist = function(){
$http({method: 'GET', url: 'http://localhost:61686/getdatlist?format=json', headers: {'Access-Control-Allow-Origin': 'localhost:*'}}).
success(function(data, status, headers, config) {
console.log(data.itemsToReturn); //I get the correct items, all seems ok here
return data.itemsToReturn;
}).
error(function(data, status, headers, config) {
console.log("fail");
});
}
return factory;
});
Any ideas about this will be great.
PS: I found a lot of posts talking about this issue but none of them helped me to get a full solution.
Thanks
Using a watch for that is kinda ugly.
try this:
datModule.factory('datfactory', function ($http, $q){
this.getlist = function(){
return $http.get('http://localhost:61686/getdatlist?format=json',{'Access-Control-Allow-Origin': 'localhost:*'})
.then(function(response) {
console.log(response); //I get the correct items, all seems ok here
return response.data.itemsToReturn;
});
}
return this;
});
datModule.controller('datlist', function ($scope, datfactory){
datfactory.getlist()
.then(function(arrItems){
$scope.items = arrItems;
});
});
This is how you use promises for async matter.
UPDATE (15.01.2015): Now even sleeker!
The issue is nothing to do with the scope digest cycle. You are trying to return from inside a callback directly, which is not asynchronously possible.
I recommend you either use a promise, or return the http promise directly.
var factory = {};
factory.getlist = function(){
return $http({method: 'GET', url: 'http://localhost:61686/getdatlist?format=json', headers: {'Access-Control-Allow-Origin': 'localhost:*'}});
}
return factory;
To return the promise directly, and handle the success/fail at factory.getlist().success()
Alternatively, use your own promise if you want to wrap additional logic around the request.
var datModule = angular.module('datModule',[]);
datModule.controller('datlist', function ($scope, datfactory){
$scope.items = [];
datfactory.getlist().then(function(data) { $scope.items = data });
});
datModule.factory('datfactory', function ($http, $q){
var factory = {};
factory.getlist = function(){
var defer = $q.defer();
$http({method: 'GET', url: 'http://localhost:61686/getdatlist?format=json', headers: {'Access-Control-Allow-Origin': 'localhost:*'}}).
success(function(data) {
// alter data if needed
defer.resolve(data.itemsToReturn);
}).
error(function(data, status, headers, config) {
defer.reject();
});
return defer.promise;
}
return factory;
});
try to initialize $scope.items = []; at controller, before call $http
I hope it helps you.
Well it looks perfect but you can use $apply like this.
datModule.controller('datlist', function ($scope, datfactory){
$scope.$apply(function() {
$scope.items = datfactory.getlist();
});
});
I think another elegant solution to this problem could be - if you are using one of the routing libraries, in my case it is the UI-Router, but could be also ngRoute, is making your controller dependent on the response of the promise, eg. adding a resolve property to the adequate state/route which doesn't let the controller load until the promise is solved and the data is ready, so in your config:
.state('datpage', {
url: '/datpage',
controller: 'DatpageController',
resolve:{
datData: function (datfactory) {
return datDataService.getData("datDataParam");
}]
},
templateUrl: 'views/datpage.html'
})
And inject the datData dependency in your controller, where you can apply it directly to the $scope:
.controller('DatpageController', function ($scope,datData) {
$scope.datPageData = datData; ...

How to pass URL params in angular $http

I'm converting a server side CRUD app to Angular.js and have a small problem.
I'm getting my data with $http and display all the data via ng-repeat. I want to make users able to click and a specific item and redirect them to the resource.
So how can I pass a URL param to the $http get call dynamically?
Here's how I built the link to the resource (car.id = 3)
<a ng-href="/#/cars/{{car.id}}">Edit</a>
The link should go to http://local.dev/#/cars/3
So how do I bind the dynamic url in my controller?
Here's a stripped down version of my controller
App.controller('CarIndexCtrl', ['$scope', '$http', '$location', function ($scope, $http, $location) {
$scope.car = {};
$http({
method: 'GET',
url: $location.$$url,
})
.success(function (data, status, headers, config) {
$scope.car = data;
})
.error(function (data, status, headers, config) {
// error
});
}]);
So I'm interested to bind the URL the angular way. The above solution works, but feels very much like a hack. I'm not that familiar with Angular, so I like to stick to the defaults for now. I might consider restangular or ng-resource at a later time though...
the above solution works, but feels very much like a hack.
I don't think its hack or something messy.
I would generate URL list in controller (from my view its better for code maintenance) without appending in HTML. Something like:
$scope.urlList = [];
$http({
method: 'GET',
url: $location.$url,
})
.success(function (data, status, headers, config) {
$scope.car = data;
$scope.urlList.push("/#/cars/" + data.id);
})
.error(function (data, status, headers, config) {
// error
});
After in HTML:
<li ng-repeat="url in urlList" repeat-done="layoutDone()" ng-cloak>
<a ng-href="{{url}}">Edit</a>
</li>
BTW, I suggest you to use some loader because URL links we generate from promise (aka async) therefore with delay.
Demo Fiddle
In your app.js do something like this
var app = angular.module('YourAPP');
app.config(function ($routeProvider) {
$routeProvider
.when('/cars/:CarID', {
templateUrl: 'app/views/cars.html',
controller: 'CarIndexCtrl'
});
});
And in your controller
App.controller('CarIndexCtrl', ['$scope', '$http', '$location', '$routeParams', function ($scope, $http, $location, $routeParams) {
$scope.car = {};
$scope.carid = $routeParams.CarID;
$http({
method: 'GET',
url: $location.$$url,
})
.success(function (data, status, headers, config) {
$scope.car = data;
})
.error(function (data, status, headers, config) {
// error
});
}]);
And use the carid in wherever in your controller. Hope it helps.

Categories