Using 'Done' instead of 'Success' in Angular promises - javascript

I've got an issue where I'm using the Contentful.js library to retrieve content in an Angular app. Instead of the normal $http.get with the success(data) callback, it uses a function with done(data). I can set the $scope.lists value to the returned data, but it does not show up in the HTML for some reason.
This works for a detail view using the standard $http:
$http.get('https://cdn.contentful.com/spaces/xxxxxxx/entries?sys.id=' + $routeParams.listId + '&include=10&access_token=xxxxxxxx').success (data) ->
$scope.list = data
console.log $scope.list
This doesn't work for a list view using the done() method:
client = contentful.createClient
accessToken: 'xxxxxxxx'
space: 'xxxxxxxxx'
listControllers.controller('ListListCtrl', ['$scope', '$http', ($scope, $http) ->
$scope.lists = ""
client.entries({'content_type': 'xxxxxxxx', 'include': 1}).done (data) ->
$scope.lists = data
console.log $scope.lists
])
Any ideas?

Most probably since this library is not targetted towards AngularJS, it is not doing $scope.$apply() to trigger digest cycle and hence the html is not getting updated.
The fix would be wrap the assingment done in callback with $scope.$apply().The JavaScript fix for this would be
$scope.$apply(function() {
$scope.lists = data
});
Since i have not use this library i may be wrong here with done callback implementation.

Related

How to show service data immediately when it is received with $http without using angular.copy?

I have a service, which should save me the specific data that I load from a JSON file. I want the data to show on the page as soon as it's received.
I created a $scope variable to be equal to the data in the service, the data is not shown immediately on the page.
I only achieved my goal when using: angular.copy(response.data, this.animals),
but I do not understand why it is not working when I am using: this.animals = response.data. I would like to know why this is happening and what is the difference.
module.service("animalService", function($http) {
this.animals=[];
$http.get('animals.json').then(function(response) {
//this.animals = response.data ----> not working
angular.copy(response.data, this.animals)
});
});
module.controller("animalController", function($scope, animalService) {
//$scope.animals is what I use to create a table in html
$scope.animals = animalService.aniamsl;
});
You are not doing it right, try:
module.service("animalService", function($http) {
return $http.get('animals.json')
});
module.controller("animalController", function($scope, animalService) {
animalService.then(function(res){
$scope.animals = res.data
});
});
any http response returns promise, and what it means is that the data would come asynchronously. As per my understanding using angular.copy triggers a digest cycle and so the changes are detected but it's not at all a good practice. Prefer promise handling as I have shown in the above code
Update:
Since the variable is populated as a promise and it is to be used by other controller , I would suggest to use events such as $rootScope.emit and $rootScope.on so that the controllers are notified about the change in value after $http is completed

[JavaScript][Angular]: TypeError: Cannot read property 'getCityData' of undefined

This question has been asked many times before and I've tried the answers but they do not seem to solve the problem I'm facing. I'm new to Angular and am trying to pass a value from the controller to a factory so that I can retrieve some JSON information through an API. While I'm able to get the value from my HTML to the controller, the next step is giving me a TypeError: Cannot read property 'getCityData' of undefined. My controller code is as follows:
app.controller('MainController', ['$scope', function($scope, HttpGetter) {
var successFunction = function(data) {
$scope.data = data;
}
var errorFunction = function(data) {
console.log("Something went wrong: " + data);
}
$scope.cityName = '';
$scope.getCityName = function(city) {
$scope.cityName = city;
HttpGetter.getCityData($scope.cityName, successFunction, errorFunction);
};
}]);
The factory code is as follows:
app.factory('HttpGetter', ['$http', function($http){
return {
getCityData: function(query, successFunction, errorFunction){
return $http.get('http://api.apixu.com/v1/current.json?key=MyAppKey&q=' + query).
success(successFunction).
error(errorFunction);
}
};
}]);
I've replaced my App key with the string "MyAppKey" just to be safe but my code contains the appropriate key. Also, it would be very helpful if I could get a bit of an insight on how the function invocations happen because there seem to be a lot of function callbacks happening.
Getting undefined could be because of the service not getting properly injected.
Try:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
Also as you said, to be on safer side you aren't using the right key, but anyone using your application can get the key by checking the network calls. So, ideally, one should make a call to the backend, and backend will send a call along with the secured key to the desired API endpoint and return the response data to front-end.
Can be due to ['$scope', function($scope, HttpGetter) ?
Should be ['$scope', 'HttpGetter', function($scope, HttpGetter) instead.
You used minified version and inject only $scope not HttpGetter but used as argument in controller function that's why got HttpGetter is undefiend and error shown Cannot read property 'getCityData' of undefined
So you should inject HttpGetter in your minified version ['$scope', 'HttpGetter'
use like:
app.controller('MainController', ['$scope', 'HttpGetter', function($scope, HttpGetter)
instead of
app.controller('MainController', ['$scope', function($scope, HttpGetter)
And if your MyAppKey is secured and want to hide from user then you should use it in server side

AngularJs local variable weird behavior

This is the code in the controller
cat1=[];
$.getJSON('categories/1/', function(data) {
cat1 = data; //returns a JSON
});
//cat2..4 are some JSONs
$scope.pictures=[cat1,cat2,cat3,cat4,cat5];
The problem is that seems like cat1=[] and cat1=data are different variables, cause pictures[cat1] always returns []
Am I doing it wrong?
Because $.getJSON is an async request and is still processing when you try and log. Also, don't use jQuery with Angular, use Angular's $http (this way a $digest cycle is triggered and everything stays in sync):
$http.get("categories/1/").success(function(data) {
cat1 = data; //returns a JSON
$scope.pictures=[cat1,cat2,cat3,cat4,cat5];
});
Dont forget to add $http as a dependency in your controller:
app.controller("myCtrl", ["$scope", "$http", function($scope, $http) {
}]);

AngularJS $http return value

I am new to AngularJS and only aware of the basics of AngularJS. I want to return a value from $http. That is $http should return a value to the global variable of My Application.
I have tried this:
var sessionValues = null;
var AdminController = angular.module('AdminController', []);
AdminController.controller('LoginController', ['$scope', '$http','$location',
function ($scope, $http, $location){
$http({
method: "post",
url: "API/MyPage.php",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data){
sessionValues = eval(data);
console.log(sessionValues); /*Returns desired string*/
}).error(function(){
$scope.message="Some error has occured";
});
console.log(sessionValues); /*Returns null */
}
]);
I tried using $rootScope, but was not successful.
I understand that this is because it is an asynchronous call, but how can I fetch the value in JS's global variable.?
Can anyone help me about this.?
The problem is indeed with the async nature of call and when you are trying to access the variable. console.log returns null because it gets called before the $http call is complete.
Firstly we do not pollute the JavaScript global scope, but use services\factory, $rootScope to access data.
In you case if you want to expose a variable to across angular, the easiest way is to use $rootScope. Something like this
AdminController.controller('LoginController', ['$scope','$http','$location','$rootScope'
function ($scope, $http, $location,$rootScope){
$http({
method: "post",
url: "API/MyPage.php",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data){
$rootScope.sessionValues = eval(data);
console.log($rootScope.sessionValues); /*Returns desired string*/
}).error(function(){
$scope.message="Some error has occured";
});
console.log($rootScope.sessionValues); /*Returns will always null due to async nature call*/
}
]);
You then have to access that variable only after it has been filled in the success call back, before that it would be always null. The console.log would always fail.
To know when the variable value has changed you can use AngularJS watch http://www.benlesh.com/2013/08/angularjs-watch-digest-and-apply-oh-my.html
I think what you want is to retrieve a constant from backend service before application loaded.
You can refer to How to retrieve constants for AngularJS from backend
In your controller, you can get the APP_CONFIG directly.
AdminController.controller('LoginController', ['$scope', '$http','$location','APP_CONFIG'
function ($scope, $http, $location, APP_CONFIG){
});
You can reuse APP_CONFIG at any angular controller, service or factory.

Angular JS Root Scope

I am working with angular js at view layer. I need to use some global variable that will be used and modified by all the controllers method in my application:
var app = angular.module('myWebservice', ['ngCookies']).run(
function($rootScope) {
$rootScope.authToken = null; });
app.controller('UserController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.login= function() {
$http.defaults.headers.post = {'Accept' : 'application/json',
'Content-Type' : 'application/json'};
$http.post('/myServise/api/user/login-user', {
emailId : $scope.username,
password : $scope.password
}).success(function(data, status) {
if (status == 200) {
$rootScope.authToken = data.object.authToken;
}).error(function(data, status) {
console.debug(data);});
}// Else end
};// End Login
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$scope.getRootScopeValues = function()
//$scope.getRootScopeValues = function($rootScope)
{
$scope.token = $rootScope.authToken;
console.log($scope.token);// Undefined
console.log($rootScope.authToken);// Undefined
}
});
I am new to Angular JS, I have also tried to use service but I don't know why I am not able to access global variable (authToken). Please help me I am stuck at this point ....Thanks in advance...
I am not sure how your application works but looks like you have a problem of asynchronous calls (while $http is working you are trying to access the variable which is not set yet). Please look at this answer about Asynchronous calls. Maybe this is your case? Also I should note that using $rootScope is always a bad idea. Try to avoid it. You should use service instead which is also a singleton object and always a much better and maintainable approach.
I need to use some global variable that will be used and modified by all the controllers method in my application
The best way to achieve this is using a Service, but you don't have to if you would like to leave it at the $rootScope
I have tried to use service as well but same results "Undefined"
Because the call for the authToken is asynchronous, the controller could run before the token returns from remote server.
You can add the token retrieval logic to the route definition as a 'resolve' field like this:
.config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/your/route', {
templateUrl: 'book.html',
controller: 'BookController',
resolve: {
token: function() {
//return a promise with the token here
}
}
})
However, this is NOT good in your case as you will have to setup the 'resolve' for every route. If you are using AngularUI Route that supports nested routes, you can simply add the 'resolve' to the root state/route. This is what I've been using in my project.
If you are not using AngularUI Route, there's another way of doing it. You can assign the returned value of the $http.post to a variable in the $rootScope e.g. $rootScope.tokenPromise.
The returned of $http.post is a promise, you can use the 'then; method to register callbacks, and these callbacks will receive a single argument – an object representing the response.
In your controller, you will have put some extra lines, you will get the token asynchronously like this
app.controller('MerchantController', function($cookieStore, $scope, $location,
$routeParams, $http, $timeout, $rootScope) {
$rootScope.tokenPromise.then( function(token){
console.log(token); //depends on the returned data structure
} )
});
In your application 'run' block, you will have to create a promise at $rootScope.tokenPromise. you can either use $http to retrieve the token and get the promise there in the run block, or create a pending promise and retrieve the token elsewhere in other places, after which you can resolve the promise.

Categories

Resources