I am using this code:
$http.get('/api/users').
success(function(data) {
$scope.authors = data;
}).
error(function() {
console.log('API error - config.')
});
And somewhere below (much bellow):
for (var i = 0; i < $scope.authors.length; i++) {
...
};
Sometimes it happens that $scope.authors are not avaliable yet. Is there any way to solve this?
UPDATE
This is the whole block structure:
// author
$http.get('/api/users').
success(function(data) {
$scope.authors = data;
processAuthors();
}).
error(function() {
console.log('API error - config.')
});
// if updating form
$scope.$on('$routeChangeSuccess', function() {
if($routeParams.id) {
$http.get('/api/offers/' + $routeParams.id).
success(function(data) {
// author
function processAuthors() {
for (var i = 0; i < $scope.authors.length; i++) {
if($scope.authors[i].email == data.author.email) {
$scope.author = $scope.authors[i];
};
};
}
Put the loop in the succes part:
$http.get('/api/users').
success(function(data) {
$scope.authors = data;
for (var i = 0; i < $scope.authors.length; i++) {
...
};
}).
error(function() {
console.log('API error - config.')
});
Yes, it doesn't matter how much below it is - you still need to call it from inside the callback because it's an async call:
function processAuthors() {
for (var i = 0; i < $scope.authors.length; i++) {
...
};
}
And then:
$http.get('/api/users').
success(function(data) {
$scope.authors = data;
processAuthors();
})
I used a function to make it look cleaner, but you can copy your code that depends on the callback inside it.
UPDATE
function processAuthors(data) {
for (var i = 0; i < $scope.authors.length; i++) {
if($scope.authors[i].email == data.author.email) {
$scope.author = $scope.authors[i];
};
};
}
$scope.$on('$routeChangeSuccess', function() {
if($routeParams.id) {
$http.get('/api/offers/' + $routeParams.id).
success(function(data) {
// author
processAuthors(data); // just call it here, define it outside
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have some code like this
I have load function, it call testRequest function.
testRequest function call ajax service and return response.
But after testRequest function run success, load function get undefined value
angular.module('MyApp', []).controller("AppCtrl", ['AjaxService', function(ajax) {
var l_this = this;
this.testRequest = function() {
var req = ajax.getstatus('https://testapi.io/api/nguyenthemanh2601/testangular');
req.then(function(rep) {
var arr = [];
if (rep.status == 400) {
for (i = 1; i < 10; i++) {
arr.push(rep.data + i);
}
return arr;
} else {
for (i = 1; i < 10; i++) {
arr.push(rep.data + i);
}
return arr;
}
});
};
this.load = function() {
var res = l_this.testRequest();
console.log(res);
l_this.status = res;
}
}]);
Please help!
angular.module('MyApp', []).controller("AppCtrl", ['AjaxService', function(ajax) {
var l_this = this;
this.testRequest = function() {
$http({
method: 'POST',
url: 'https://testapi.io/api/nguyenthemanh2601/testangular',
}).
success(function(rep) {
if (rep.status == 200) {
for (i = 1; i < 10; i++) {
arr.push(rep.data + i);
}
return arr;
}
}).
error(function(rep) {
if (rep.status == 400) {
for (i = 1; i < 10; i++) {
arr.push(rep.data + i);
}
return arr;
}
});
};
// Next Execution.....
}]);
Note You can handle success and error message based on that response execute the next step(handle error and success).
more info... $http request angular
I created a video gallery application like Youtube using AngularJS. There's a REST API and I am calling that REST URLs via Angular services.
Here's are two controller files and they have most probably same functionality, but calling different URL to get different videos.
This is BoxsetCtrl.js file and it get all the Boxset videos(a category name). This is the full controller file.
angular.module('data_visualize')
.controller('BoxsetCtrl', function ($scope, boxsetService) {
$('html,body').scrollTop(0);
$scope.allBoxsets = [];
$scope.count2 = parseInt(0);
$scope.scene = {
sort2: "most_recent"
};
/**
* Loading all the box sets with limit and offset.
*/
boxsetService.viewAllBoxSetsByDate(0).then(function (data) {
$scope.allBoxsets = data;
});
$scope.getSceneSortByValue = function () {
$scope.count2 = parseInt(0);
$scope.sort2Value = $scope.scene.sort2;
console.log($scope.scene.sort2);
if ($scope.sort2Value == 'most_recent') {
boxsetService.viewAllBoxSetsByDate(0).then(function (data) {
$scope.allBoxsets = data;
});
} else if ($scope.sort2Value == 'popularity') {
boxsetService.viewAllBoxSetsByPopularity(0).then(function (data) {
$scope.allBoxsets = data;
});
} else if ($scope.sort2Value == 'name') {
boxsetService.viewAllBoxSetsByName(0).then(function (data) {
$scope.allBoxsets = data;
});
} else if ($scope.sort2Value == 'number_of_scenes') {
boxsetService.viewAllBoxSetsByScenes(0).then(function (data) {
$scope.allBoxsets = data;
});
} else {
boxsetService.viewAllBoxSetsByDate(0).then(function (data) {
$scope.allBoxsets = data;
});
}
};
$scope.getSelectedLetter = function (letter) {
$scope.count2 = parseInt(0);
$scope.scene.sort2 = "by_letter";
$scope.selectedLetter = letter;
console.log($scope.selectedLetter);
boxsetService.viewAllBoxSetsByLetter(letter, 0).then(function (data) {
$scope.allBoxsets = data;
});
};
$scope.resetLetterFilter = function () {
$scope.scene.sort2 = 'most_recent';
boxsetService.viewAllBoxSetsByDate(0).then(function (data) {
$scope.allBoxsets = data;
});
};
$scope.loadByNumbers = function () {
$scope.scene.sort2 = 'by_numbers';
boxsetService.viewAllBoxSetsByNumber(0).then(function (data) {
$scope.allBoxsets = data;
});
};
$(window).scroll(function () {
if ($(window).scrollTop() + $(window).height() > $(document).height() - scrollZise) {
$scope.count2 = $scope.count2 + 8;
console.log("New count box set : ", $scope.count2);
if ($scope.scene.sort2 == 'most_recent') {
boxsetService.viewAllBoxSetsByDate($scope.count2).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
} else if ($scope.scene.sort2 == 'popularity') {
boxsetService.viewAllBoxSetsByPopularity($scope.count2).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
} else if ($scope.scene.sort2 == 'name') {
boxsetService.viewAllBoxSetsByName($scope.count2).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
} else if ($scope.scene.sort2 == 'number_of_scenes') {
boxsetService.viewAllBoxSetsByScenes($scope.count2).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
} else if ($scope.scene.sort2 == 'by_letter') {
boxsetService.viewAllBoxSetsByLetter($scope.selectedLetter, $scope.count2).then(function (data) {
console.log("Sekected letter : ", $scope.selectedLetter);
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
} else if ($scope.scene.sort2 == 'by_numbers') {
boxsetService.viewAllBoxSetsByNumber($scope.count2).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allBoxsets.push(data[i]);
}
});
}
}
});
});
This is a controller which loading Boxsets. And also there's another controller which uses to get some other scenes. Here's that controller.
angular.module('data_visualize')
.controller('SceneCtrl', function ($scope, sceneService) {
$('html,body').scrollTop(0);
/**
* Initializing and defining all the
* arrays and variables.
* #type {Array}
*/
$scope.allScenes = [];
$scope.count = parseInt(0);
$scope.scene = {
sort: "most_recent"
};
/**
* Loading all the scenes with limit and offset.
* Default page load invoke method for data set.
*/
sceneService.viewAllScenesByDate(0).then(function (data) {
$scope.allScenes = data;
});
$scope.getVideosByLetter = function (event) {
console.log("Filter : ", $scope.filter);
if ($scope.filter == "" || $scope.filter == null) {
sceneService.viewAllScenesByDate(0).then(function (data) {
$scope.allScenes = data;
});
} else {
$scope.scene = {
sort: "by_letter"
};
sceneService.viewAllScenesByLetter($scope.filter, 0).then(function (data) {
$scope.allScenes = data;
console.log(data);
});
}
};
/**
* Get drop down value and send to server
* in order to get the response.
*/
$scope.getSceneSortByValue = function () {
$scope.count = parseInt(0);
$scope.sortValue = $scope.scene.sort;
console.log($scope.sortValue);
if ($scope.sortValue == 'most_recent') {
sceneService.viewAllScenesByDate(0).then(function (data) {
$scope.allScenes = data;
});
} else if ($scope.sortValue == 'popularity') {
sceneService.viewAllScenesByPopularity(0).then(function (data) {
$scope.allScenes = data;
});
} else if ($scope.sortValue == 'name') {
sceneService.viewAllScenesByName(0).then(function (data) {
$scope.allScenes = data;
});
} else {
sceneService.viewAllScenesByDate(0).then(function (data) {
$scope.allScenes = data;
});
}
};
/**
* Detect window scroll and send request
* to sever to get the real time pagination.
*/
$(window).scroll(function () {
if ($(window).scrollTop() + $(window).height() > $(document).height() - scrollZise) {
$scope.count = $scope.count + 8;
console.log("NEW Count scene: ", $scope.count);
if ($scope.scene.sort == 'most_recent') {
sceneService.viewAllScenesByDate($scope.count).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allScenes.push(data[i]);
}
});
} else if ($scope.scene.sort == 'popularity') {
sceneService.viewAllScenesByPopularity($scope.count).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allScenes.push(data[i]);
}
});
} else if ($scope.scene.sort == 'name') {
sceneService.viewAllScenesByName($scope.count).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allScenes.push(data[i]);
}
});
} else if ($scope.scene.sort == 'by_letter') {
sceneService.viewAllScenesByLetter($scope.filter, $scope.count).then(function (data) {
for (var i = 0; i < data.length; i++) {
$scope.allScenes.push(data[i]);
}
});
}
}
});
});
These are two controllers which has two different views. When those views are scrolling, data is loading as Pagination. Here's a sample HTML code of HTML view. Data is loading with ng-repeat.
<div ng-repeat="data in allBoxsets">
<div class="col-lg-3 col-md-4 col-xs-6">
<a class="thumbnail" href="#/boxset/{{data.seriesid}}">
<img class="img-responsive" src="lib/images/banner_selection/films/gallery/{{data.imagepath}}"
alt="">
<div class="row">
<div class="col-lg-12">
{{data.seriesname}}
</div>
<div class="col-lg-12">
Views : {{data.views}}
</div>
<div class="col-lg-12">
Scenes : {{data.scenes}}
</div>
</div>
</a>
</div>
</div>
But here's the problem, when I'm viewing Scenes using SceneCtrl, they are loading, but the problem is Boxset controller is also getting activated and when the page scrolls, those boxset requests are going to the server too. So it's really slow to load data. What's the problem for this? Is there any way to make this working properly.
When I'm using Scenes, I only need to activate SceneCtrl and when I'm using Boxsets, I only need to use BoxsetCtrl.
Any suggestions are welcome.
Basically, the easy way for you is to make use of either ng-route or ui-router. I suggest the latter one. This way you can clearly mention the view and the controller associated with that view, you can also make use of other advance features which are provided by the 'ui-router'.
For example look at below code:
angular.module('app', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
// State definitions
$stateProvider
.state('homeState', {
url: '/home',
template: '<div> {{ title }} ' +
'<button data-ng-click="gotoState(\'homeState.stateA\')" >GoTo A</button>' +
'<button data-ng-click="gotoState(\'homeState.stateB\')" >GoTo B</button>' +
'<div ui-view><div>' +
'</div>',
controller: 'HomeController'
})
.state('homeState.stateA', {
url: '/stateA',
template: '<div> {{ data }} </div>',
controller: 'StateAController'
})
.state('homeState.stateB', {
url: '/stateB',
template: '<div> {{ data }} </div>',
controller: 'StateBController'
});
// Default to stateA
$urlRouterProvider.otherwise('/home');
})
.controller('HomeController', function($scope, $state) {
// homeState data
$scope.title = 'State example';
$scope.gotoState = function(stateName) {
$state.go(stateName);
};
})
.controller('StateAController', function($scope) {
// StateA data
$scope.data = 'Hi State A';
})
.controller('StateBController', function($scope) {
// StateB data
$scope.data = 'Hi State B';
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.4.2/angular-ui-router.min.js"></script>
<div data-ng-app="app">
<!-- This is the ui-view, marks the area where the content should be rendered -->
<div ui-view></div>
</div>
I want a route based authorization through AngularJS. I tried but wasn't able to find the right solution.
var app = angular.module('app', []);
var mycontroller = app.controller('mycontroller', function ($rootScope, authService) {
});
app.service('authService', function ($http, $rootScope) {
var userRole = ['ROLE_USER']; // this will come from database,
var userRoleRouteMap = {
'ROLE_ADMIN': [ '/dashboard', '/about-us', '/authError' ],
'ROLE_USER': [ '/usersettings', '/usersettings/personal', '/authError']
};
return {
userHasRole: function (role) {
for (var j = 0; j <= userRole.length; j++) {
if (role == userRole[j]) {
return true;
}
}
return false;
},
isUrlAccessibleForUser: function (route) {
for (var i = 0; i <= userRole.length; i++) {
var role = userRole[i];
var validUrlsForRole = userRoleRouteMap[role];
if (validUrlsForRole) {
for (var j = 0; j <= validUrlsForRole.length; j++){
if (validUrlsForRole[j] == route)
return true;
}
}
}
return false;
}
};
});
app.run(function ($rootScope) {
// This Block is not working i want to see the url change every time from here.
$rootScope.$on("$locationChangeStart", function (event, next, current) {
// handle route changes
console.log(next); // this is not working
if (!authService.isUrlAccessibleForUser("/about-us"))
$location.path('/authError');
});
});
I have a LIST of Id's and I want all of them to contact my API.
The way I did it is like this:
var someFunct = function() {
for (var i = 0; i < Apples.length; i++) {
var Apple = Apples[i];
$http.get("APIUrl" + Apple.Id).
success(function (response) {
for (var i = 0; i < response.Appleseeds.length; i++) {
if(Apple.Appleseeds.Id == response.Appleseeds.Id)
{
Apple.Size = response.Appleseeds.Size;
}
}
})
}
So the problem is that Apple[2] has changed value, where Apple[0] and Apple[1] stay untouched. response.Appleseeds have their own list of Id's. So I need to change the Size of ALL THE APPLES not just Apple[2].
You're close, use a closure instead:
var someFunct = function () {
for (var i = 0; i < Apples.length; i++) {
(function (Apple) {
$http.get("APIUrl" + Apple.Id)
.success(function (response) {
for (var i = 0; i < response.Appleseeds.length; i++) {
if (Apple.Appleseeds.Id == response.Appleseeds.Id) {
Apple.Size = response.Appleseeds.Size;
}
}
});
})(Apples[i]);
}
};
Because http doesn't happen instantly, by the time the last success has happened in your code apple has been changed. By wrapping it in a closure you make it so that each call has it's own private Apple.
var deferred = $q.defer();
var someFunct = function() {
for (var i = 0; i < Apples.length; i++) {
$http.get("APIUrl" + Apples[i].Id).
success(function (response) {
deferred.resolve(response)
})
return deferred.promise;
}
}
someFunct().then(function(d)){
// write your code here
}
I have two angularjs function in my dataContext object that receive data from an webapi as you can see below
(function () {
'use strict';
var serviceId = 'datacontext';
angular.module('app').factory(serviceId,
['common', datacontext]);
function datacontext(common) {
var service = {
getAllTagsByHttp: getAllTagsByHttp,
getBlogPostsByHttp: getBlogPostsByHttp,
getAllUserPicByHttp: getAllUserPicByHttp
};
return service;
function getAllTagsByHttp() {
return common.$http.get('/api/TagApi/alltags');
}
function getBlogPostsByHttp() {
return common.$http.get('/api/BlogPostApi/AllBlogPosts');
}
function getAllUserPicByHttp() {
return common.$http.get('/api/BlogPostApi/AllUserPic');
}
}})();
I have an angularjs controller that call these api functions from the datacontext to receive information to display back to the user. The getblogPost function is called first because the next function need's the data from this to operate on.the second function does a comparison on the first function's data to display back the img source to the user. The problem i am having is that it takes quite a few seconds for the second function to receive the data and an complete its operation. The amount of data being send back is a few records.Is there any improvements that can be made to controller or data Context object to reduce the time or improve the code?
(function () {
'use strict';
var controllerId = 'search';
angular
.module('app')
.controller(controllerId, ['common','datacontext', search]);
function search(common, datacontext) {
var getLogFn = common.logger.getLogFn;
var log = getLogFn(controllerId);
var vm = this;
vm.title = 'search';
vm.picData = [];
activate();
function activate() {
var promises = [getBlogPosts(), getUserPicData(), getUserPicUrl()];
common.activateController(promises, controllerId)
.then(function () { log('Search View'); });
}
function getBlogPosts() {
datacontext.getBlogPostsByHttp().then(function (response) {
vm.data = response.data;
});
}
function getUserPicData() {
datacontext.getAllUserPicByHttp().then(function (response) {
vm.picData = response.data;
for (var i = 0; vm.data.length > i; i++) {
for (var x = 0; vm.picData.length > x; x++) {
if (vm.data[i].UserName == vm.picData[x].UserName) {
vm.data[i].PictureUrl = vm.picData[x].PictureUrl;
// console.log(vm.data[i].PictureUrl);
break;
}
}
}
});
}
function getUserPicUrl(username) {
getUserPicData();
for (var i = 0; vm.picData.length < i; i++) {
if (vm.picData[i].UserName === username) {
return vm.picData[i].PictureUrl;
}
}
return "not found";
}
}})();