AngualrJS Undefined or Null Reference When Accessing $rootSope in Controller - javascript

AngularJS latest release candidate:
I am putting a javascript object - called say stuff into the $rootScope from the module's run function, which I believe is supposed to block. This is the code:
'use strict';
/* App Module */
var app = angular.module('MyApp', ['ngRoute', 'API'])
.run(function ($rootScope, API) {
$rootScope.stuff = null;
// call the API
API.getStuff()
.success(function(data){
$rootScope.stuff = data;
})
.error(function(data){
$rootScope.stuff = null;
});
});
Now, when I attempt to access the stuff property of $rootScope from my controller, I am getting an 'undefined or null reference' error on stuff. Code looks like this:
'use strict';
app.controller('indexController',
function ($scope, $rootScope, otherAPI) {
var
stuff = $rootScope.stuff;
// call the other API
otherAPI.getDifferentStuff(stuff.property)
.success(function(data){
$scope.differentStuff = data;
})
.error(function(data){
// do some error handling stuff here
});
});
I know the api call in the run function is succeeding, and it is assigning a value to stuff in the $rootScope. Can anyone see anything obvious wrong with my code here?
Thanks for any help!
Rich

Is API.getStuff an asynchronous api call (it looks like it). In that case most likely your controller is getting initialized before the asynchronous call has returned, so $rootScope.stuff is still equal to null. If you wait until the call succeeds, then you will have your data.

Related

$scope or $http vs. response or reason in AngularJS

I started learning Angular JS two hours ago and saw this in the tutorial:
var app = angular.module("githubViewer", []);
var MainController = function($scope, $http){
var onUserComplete = function(response){
$scope.user = response.data;
};
var onError = function(reason){
$scope.error = "Failed to get the user info.";
};
var promise = $http.get("https://api.github.com/users/someone");
promise.then(onUserComplete, onError);
};
app.controller("MainController", MainController);
I understand $scope/$http is native to Angular but what about the response/reason? How are they passed to the function?
Those are the callback functions - onUserComplete and onError, which are called when the promise returned by $http.get() function is resolved. The callback functions are passed response returned by the completion of $http.get() invocation. The parameter in the function is that response.
#Rohit Jain is right.
This is much more a related to Javascript then Angular.
CallBack are often used in JS.
Here is a quick exemple to understand how CallBack works
function mainFunc(mycallBack){
mycallBack()
}
function onSomething(){
alert("hi");
}
mainFunc(onSomething);
http://plnkr.co/edit/Ud1E6Wbns1EnItVI8Xg7?p=preview
I hope it helps.
Regards,
Eric

Angular JSONP Factory call not working, however it does work in controller

I have looked at every post on SO related to this issue but still cannot find the answer. This response appeared to be the most promising but I didn't understand the answer, and it appears the person who asked did not either.
What am I trying to do?
Make a JSONP angular GET request to the itunes API. This works perfectly when I make the GET request from my controller, however when I tried to refactor, in order to obey the principle of 'Separation of Concerns' by moving this request into a factory, and injecting into the controller I am running into difficulties. I know the call is still being made as I am getting a CORS error if I do not use a JSONP call in my factory.
Here is the factory code:
var myApp = angular.module('jDillaApp', []).factory('Music', function ($http) {
var o = {
songs: []
};
o.getNextSongs = function () {
return $http.jsonp({
method: 'GET',
url: 'https://itunes.apple.com/search?term=j+dilla&limit=25?format=jsonp&callback=JSON_CALLBACK'
}).success(function (data) {
console.log(data)
});
}
return o
})
My controller looks like this:
myApp.controller('jDillaCtrl', ['$scope', '$http', 'Music',
function ($scope, $http, Music) {
Music.getNextSongs();
$scope.songs = Music.songs;
var media = new Audio();
$scope.playSong = function () {
media.pause();
var randomSong = Math.round(Math.random() * ($scope.songs.length - 1));
media = new Audio($scope.songs[randomSong]);
media.play();
}
}]);
The error is not a lot of help as far as I can tell but worth posting anyway TypeError: h.replace is not a function
You $http.jsonp method has wrong inputs that was your first problem, $http.jsonp method accepts two parameter as such
$http.jsonp(url, [config])
url -> the url which you want make an ajax
config -> if you want to make additional changes in request then you can pass those setting from here in {} key value pair like you can set headers, type, etc.
Your service method should return promise, as you only need to return $http.jsonp object which already has promise, no need of creating extra promise object here.
Service
o.getNextSongs = function () {
return $http.jsonp('https://itunes.apple.com/search?term=j+dilla&limit=25?format=jsonp&callback=JSON_CALLBACK')
}
In controller that call will be resolved using .success & .error also you can use .then
Controller
Music.getNextSongs()
.success(function (data) {
//here you get the ajax success
console.log(data)
});

Angularjs not storing variable to $scope after AJAX call within $http.get request

I'm using angularjs and I can't get the following controller to save to a $scope variable the data returned from an AJAX request to Flickr. The $http.get makes a call to a locally saved json file. Upon success, it uses the json returned in success() to determine the appropriate url for the AJAX call to the Flickr API. Upon success of that call, I log the data to the console. So far so good, it returns an array of three objects. However, I'm trying to set that array to a $scope variable ($scope.photos) so I can iterate over it my view template. However, when I try outputing {{photos}} in the html there is nothing. I suspect this is a promise issue, and the template is rendering before the AJAX returns the data from Flickr, but I've been pouring over the docs with no success (looked at $q a little). I'm somewhat new to Angular and would appreciate your insight. Thanks!
artistControllers.controller('PhotoController', ['$scope', '$http', '$routeParams', '$q', function ($scope, $http, $routeParams, $q){
$http.get('js/data.json').success(function(data){
$scope.artists = data;
$.ajax({
type : "GET",
dataType : "jsonp",
url : $scope.artists[$routeParams.itemId].flickr,
success: function(flickr){
$scope.photos = flickr.items;
console.log($scope.photos);
}
});
});
}]);
Don't use jQuery.ajax. Angular's $http can do JSONP too. You can read more about here.
artistControllers.controller('PhotoController', ['$scope', '$http', '$routeParams', '$q', function ($scope, $http, $routeParams, $q){
$http.get('js/data.json').success(function(data){
$scope.artists = data;
$http.jsonp($scope.artists[$routeParams.itemId].flickr).success(function(data){
$scope.photos = flickr.items;
console.log($scope.photos);
});
});
}]);
Because you are executing code outside of Angular's knowledge, you need to manually call $scope.$digest() for it to "see" your change and update the markup accordingly.
Just change your success handler to:
success: function(flickr){
$scope.photos = flickr.items;
$scope.$digest();
}
Note: $scope.$apply() would also work, because it does a $digest of every single scope in your application, starting from the $rootScope down. On a big application, this can be much slower than necessary, so in your case I recommend only digesting from the scope you are modifying down.
Thank you everyone for your help and feedback. I have found a solution using $q and $http.jsonp, in part thanks to this tutorial:
http://youtu.be/gApduktFwxw?t=17m
Here is my code, note that my API url string to flickr has &jsoncallback=JSON_CALLBACK appended to it:
$http.get('js/data.json').success(function(data){
$scope.artist = data[$routeParams.itemId];
var url = $scope.artist.flickr;
console.log(url);
$scope.init = function(){
$scope.getImages()
.then(function(res){
console.log(res);
}, function(status){
console.log(status);
});
};
$scope.getImages = function(){
var defer = $q.defer();
$http.jsonp(url)
.success(function(res){
defer.resolve(res);
console.log(res);
}).error(function(status, err){
defer.reject(status);
console.log(err);
});
return defer.promise;
};
$scope.init();

Site-wide error message broadcast in Angular

I have a single way of showing the user if there is an error with a $http call, and I currently invoke it by doing something like:
$http({
//do stuff
}).
error(function(){
$scope.$broadcast('error');
});
And I have a directive that listens for the the error with $on.
However I just end up repeating the $broadcast everywhere I use $http, is it possible to extend the default error callback to broadcast the error every time?
I would suggest you use a response interceptor instead.
You can find the details on the AngularJS API Reference, but this is how it would work:
angular.module('app', []);
angular.module('app').factory('myHttpErrorInterceptor', function ($q) {
return {
'responseError': function (rejection) {
console.log('DEBUG: Status:', rejection.status);
return $q.reject(rejection);
}
};
});
angular.module('app').config(function ($httpProvider) {
$httpProvider.interceptors.push('myHttpErrorInterceptor');
});
angular.module('app').run(function ($http) {
$http.get('http://example.org/that-doesnt-exist');
});
Instead of my console.log, you can broadcast your error instead.
You can find a live example here.

Pass data from service to controller

I'm trying to pass data from a service to a controller in angular js, the code is the following:
.controller('lista',function($scope,cetrams){
$scope.hola="This is it";
var test;
var testfn = function(){
test = 'Lala';
};
cetrams.success(function(data){
testfn();
test = data;
console.log('Inside service: '+test);
});
console.log('Inside controller: '+test);
})
The service is working, as I get the promise and the function for success is executed, but I cannot get the variable outside that function to the controller scope.
If you are expecting the value to be available at the last line
console.log('Inside controller: '+test);
then you are incorrect. Due to async nature of the code the last line would get executed before the service returns with data.
Your logic should be done in the success method or use $scope.$watch to watch the test variable for change

Categories