How do i define a global variable from asynchronous call with angularjs? - javascript

I want to use single_video variable in outside of the controller function. It prints well in first console log. However it gives a single_video is undefined error in second console.log which is outside of the controller function. Because of the asynchronousity.
var single_video;
var app = angular.module('myApp', []);
app.controller('randomVideo', function($scope, $http) {
var onSuccess = function(response){
$scope.video = response.data;
single_video = $scope.video;
//First console.log
console.log('1st ID='+single_video.yt_id);
};
var onError = function(reason){
$scope.error = "There is an error about getting random_video.php";
};
$http.get("http://www.ytmdb.com/ytvideo/api/random_video.php")
.then(onSuccess, onError);
});
//Second console.log
console.log('2nd ID='+single_video.yt_id);

You can create a function that you invoke inside the success callback passing your variable as a parameter to the function:
var app = angular.module('myApp', []);
app.controller('randomVideo', function($scope, $http) {
var onSuccess = function(response){
$scope.video = response.data;
single_video = $scope.video;
//First console.log
console.log('1st ID='+single_video.yt_id);
test(single_video.yt_id);
};
var onError = function(reason){
$scope.error = "There is an error about getting random_video.php";
};
$http.get("http://www.ytmdb.com/ytvideo/api/random_video.php")
.then(onSuccess, onError);
});
function test(a)
{
console.log('2nd ID='+a);
}

Define your global variables in a factory service and inject the service in your angular controller where ever you need. (Note: try to put everything in an IIFE)
Global Variables using services, here is an example:
var myApp = angular.module('myApp',[]);
myApp.factory('MySvc', function() {
return {
name : 'your name'
};
});
and in a controller:
function MyCtrl($scope, MySvc) {
$scope.name = MySvc.name;
}

Related

Testing if callback have been called using $rootScope.$broadcast and $scope.$on

I've been trying testing if a callback have been called on my controller.
Controller
(function () {
'use strict';
angular
.module('GeoDashboard')
.controller('CiudadCtrl', CiudadCtrl);
CiudadCtrl.$inject = ['$scope', '$interval', '$rootScope','Ciudad'];
function CiudadCtrl($scope, $interval, $rootScope, Ciudad) {
$scope.refreshCiudad = refreshCiudad;
$scope.refreshClima = refreshClima;
var removeListenerRefreshCiudad = $scope.$on('refreshCiudad', refreshCiudad);
var cancelIntervalIdClima = $interval(refreshClima, 600000);
function refreshCiudad() {
//...
}
}
})();
Testing
beforeEach(inject(eachSpec));
function eachSpec($rootScope, $controller, $httpBackend, $interval, _Ciudad_){
rootScope = $rootScope;
scope = $rootScope.$new();
httpBackend = $httpBackend;
interval = sinon.spy($interval);
CodificacionGeograficaService = _CodificacionGeografica_;
CiudadService = _Ciudad_;
CiudadController = $controller('CiudadCtrl', {
$scope : scope,
$interval: interval,
Ciudad: CiudadService
});
}
it('3. Debería llamar a "refreshCiudad" al escuchar el evento "refreshCiudad"', spec3);
function spec3(){
sinon.spy(scope, 'refreshCiudad');
rootScope.$broadcast('refreshCiudad');
expect(scope.refreshCiudad).toHaveBeenCalled();
scope.refreshCiudad.restore();
}
But when I trying to emit a $broadcast event, the callback is not have been called.
What i've doing wrong?
Finally This is working, but I don't understand why.
The solution was wrap the callback function for $scope.$on in another function like this
function CiudadCtrl($scope, $interval, $rootScope, Ciudad) {
$scope.refreshCiudad = refreshCiudad;
//instead this
//var removeListenerRefreshCiudad = $scope.$on('refreshCiudad', refreshCiudad);
//I set the callback like this
var removeListenerRefreshCiudad = $scope.$on('refreshCiudad', function(){
$scope.refreshCiudad(); //And this work!
});
function refreshCiudad() {
//...
}
}

Angular $scope object showing $scope.data but when I try to use it, the says undefined

I have this controller that takes info from a service.
When I return the data to the controller I am using $scope to let the view have the data.
I have a few console.logs and the ones inside the then function work fine. However outside, the $scope object that gets logged has a .data but when I try to console.log it, it comes back as an empty object.
Is there something in my code that's wrong?
(function() {
angular
.module("eplApp")
.controller("tableCtrl", TableController);
TableController.$inject = ['httpService', "$scope"];
function TableController(service, $scope) {
var apiTableUrl = "http://api.football-data.org/v1/soccerseasons/426/leagueTable";
$scope.data = {};
service.getListFromUrl(apiTableUrl).then(function(data) {
$scope.data = data;
console.log($scope);
console.log($scope.data);
});
console.log($scope);
console.log($scope.data);
}
})();
Angular is asynchronous, that's why you can't console it outside service response
Try to print the data this way..
function TableController(service, $scope) {
$scope.data = {};
service.getListFromUrl(apiTableUrl).then(function(data) {
$scope.data = data;
printData();
});
function printData() {
console.log($scope.data);
}
}

How do I add result to my scope ng-click?

This is a relatively simple piece of code that calls a service and returns some data. I need to set the $scope with the result of the data. Is there an easy way to set this data to the scope without resorting to to binding the scope to the function in the then clause?
Angular Code
(function () {
var app = angular.module('reports', []);
var reportService = function($http, $q) {
var service = {};
service.getMenuData = function() {
var deffered = $q.defer();
$http.get('/Report/MenuData').success(function(data) {
deffered.resolve(data);
}).error(function(data) {
deferred.reject("Error getting data");
});
return deffered.promise;
}
return service;
};
reportService.$inject = ['$http', '$q'];
app.factory('reportService', reportService);
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = function(e) {
reportService.getMenuData().then(function(data) {
// Need to set the $scope in here
// However, the '$scope' is out of scope
});
}
};
reportMenuController.$inject = ['$scope', '$http', 'reportService'];
app.controller('ReportMenuController', reportMenuController);
})();
Markup
<div>
<div ng-controller="ReportMenuController">
<button ng-click="getMenuData()">Load Data</button>
</div>
</div>
There is absolutely no problem to set the $scope from within the function passed to then(). The variable is available from the enclosing scope and you can set your menu data to one of its fields.
By the way: You should consider to use then() instead of success() for your http request. The code looks much nicer because then() returns a promise:
service.getMenuData = function() {
return $http.get('/Report/MenuData').then(function(response) {
return response.data;
}, function(response) {
deferred.reject("Error getting data");
});
}
success() is deprecated by now.
I didn't notice the small detail missing in the plunker where my code was different.
(function () {
...
var reportMenuController =
function ($scope, $http, reportService) {
$scope.getMenuData = getMenuData;
function getMenuData(e) {
reportService.getMenuData().then(function(data) {
// Now I have access to $scope
});
}
};
...
})();
Notice the changes to the two lines as below:
$scope.getMenuData = getMenuData;
function getMenuData(e) {
This also begs a small question which is, "Why is it okay to set getMenuData to the $scope before it is declared?

Karma testing a call to a function inside a scope.function

I have a UploadDocumentCtrl.js where i am accessing a service call to a function inside another function . This outer function is bound to the scope . My problem is i am unable to access the code statements inside this (Code block C) . I want to access the 'flag' variable and check if that is true . Can anyone point me in the correct direction or tell me what i am doing wrong here ? Thanks ..
UploadDocumentsCtrl.js
(function () {
'use strict';
angular.module('myApp')
.controller('UploadDocumentsCtrl', UploadDocumentsCtrl);
UploadDocumentsCtrl.$inject = ['$rootScope', '$scope', '$modalInstance', '$window', 'companyService'];
function UploadDocumentsCtrl($rootScope, $scope, $modalInstance, $window, companyService) {
$scope.onFileSelect = onFileSelect;
$scope.buttonDisabled = false;
function onFileSelect(files) {
//Can access the code here
function upload(file) {
//Can access the code here as well
companyService.uploadDocuments(file)
.success(function (data, status, headers, config) {
// Code block C
// Cannot access any code here or the error code block below
$scope.flag = true;
})
.error(function (data, status, headers, config) {
});
}
files.forEach(function (file) {
file.progress = 0;
file.percent = 0;
$scope.filesToUpload.push(file);
upload(file);
});
}
}
})();
Jasmine test case
(function () {
"use strict";
describe('UploadDocumentsCtrl', function () {
var scope, companyService,companyControllerFactory;
beforeEach(angular.mock.module('myApp'));
beforeEach(inject(function($rootScope, $controller , _companyService_) {
companyService = _companyService_;
scope = $rootScope.$new();
companyControllerFactory = function(){$controller('UploadDocumentsCtrl',
{
$scope: scope,
companyService: _companyService_
});
};
}));
describe("onFileSelect", function() {
it(" Should make the flag to true ", function() {
var files = [{}];
companyControllerFactory();
spyOn(companyService, 'uploadDocuments').and.returnValue({ success: function(){}});
scope.onFileSelect(files);
expect(scope.flag).toBe(true);
});
});
});
})();
The error i am getting while trying to do the above..
1) Should make the flag to true
UploadDocumentsCtrl onFileSelect
TypeError: companyService.uploadDocuments(...).success(...) is undefined in http://localhost:9876/absoluteC:/Users
/Documents/fle/Fle/WebApiRole/app/company/UploadDocumentsCtrl.js?f11d5dcacbf2ca1d63778bfa04c582862e325523
( line 31)
upload#http://localhost:9876/absoluteC:/Users/Documents/fle/Fle/WebApiRole/app/company/UploadDocumentsCtrl
.js?f11d5dcacbf2ca1d63778bfa04c582862e325523:31:17
onFileSelect/<#http://localhost:9876/absoluteC:/Users/Documents/fle/Fle/WebApiRole/app/company/UploadDocum
entsCtrl.js?f11d5dcacbf2ca1d63778bfa04c582862e325523:51:17
onFileSelect#http://localhost:9876/absoluteC:/Users/Documents/fle/Fle/WebApiRole/app/company/UploadDocumen
tsCtrl.js?f11d5dcacbf2ca1d63778bfa04c582862e325523:46:13
#http://localhost:9876/base/test/company/UploadDocumentsCtrlSpec.js?c5db561e203bdfae1a6f7509347d3f7032e8f785:35:17
In my project I am using below format to spy service. You can try below option:
var deffered = q.defer();
spyOn(companyService, 'uploadDocuments').and.returnValue(deffered.promise);
deffered.resolve();
And to apply this you will have to use $rootScope.$apply() before assert (i.e. before expect())
Is companyService making an http call?
If so, you'll need to mock the response with $httpBackend and then get to the proper conditions based on the mocked response using $httpBackend.flush().

how to update $scope object in a view after a promise is resolved in angular?

i have a simple situation where in the controller I have:
$scope.loadEvents = function () {
var items = listEvents(id);
items.then(function (data) {
$scope.test= data;
});
};
In the view I do:
<h1>{{test}}</h1>
but $scope.test is not available yet. If I do $scope.apply() I get this error
the actual error is that {{test}} doesn't show, i guess because is undefined
any ideas?
You can do
$scope.test = [];
$scope.loadEvents = function () {
var items = listEvents(id);
items.then(function (data) {
$scope.test= data;
});
};
and in view
<h1 ng-if="test">{{test}}</h1>
to make it visible only when test is loaded

Categories

Resources