Using $timeout in service: this.func is not a function - javascript

I've been trying to use promise to end user session after certain amount of time.
Problem is, whenever a function defined in service is called from the function triggered by $timeout, the function seems to be undefined. I think it's some kind of a scope issue, but I have not managed to fix this on my own.
app.service('sessionService', function($timeout) {
var closeSession = function() {
this.resetUserInfo()
// maybe do other things as well
}
this.start = function() {
console.log("start")
promise = $timeout(closeSession, sessionLength)
}
this.resetUserInfo = function() {
// reset session
}
}
Error: this.resetUserInfo is not a function
Things I have tried
different ordering of functions
this.closeSession instead of var
$timeout(function(){closeSession(this.resetUserInfo)}, sessionLength) with proper modifications to closeSession

Note this assigned to that. So you are using the scope of the service instead of the scope of the method.
app.service('sessionService', function($timeout) {
var that = this;
var closeSession = function() {
that.resetUserInfo()
// maybe do other things as well
}
this.start = function() {
console.log("start")
promise = $timeout(closeSession, sessionLength)
}
this.resetUserInfo = function() {
// reset session
}
}

An alternative would be to make resetUserInfo a local function and then attach to it this later on. For example:
app.service('sessionService', function($timeout) {
//private definition
var resetUserInfo = function() {
}
var closeSession = function() {
resetUserInfo(); //call the private version
}
this.start = function() {
console.log("start")
promise = $timeout(closeSession, sessionLength)
}
//now expose method as public here
this.resetUserInfo = resetUserInfo;
}

Related

How to run the service on page load

I have the function inside service in angular module but how do I run the service on page load. I am not using any controller here
Code:
var app = angular.module("myTmoApppdl", [])
.service('populatePageObjsService', function () {
var self = this;
//digitalData is a global object
self.populatePage = function (digitalData) {
var dataPageObject = document.getElementById('metaJson').getAttribute("data-pageObject");
var jsonPageObject = JSON.parse(dataPageObject);
for (var key in jsonPageObject.page.pageInfo) {
var value = jsonPageObject.page.pageInfo[key];
if (digitalData.page.pageInfo.hasOwnProperty(key)) {
digitalData.page.pageInfo[key] = value;
}
}
console.log("Page data populated successfully: ", digitalData.page.pageInfo);
}();
});
I tried using the () after function but it didn't execute the function
Update:
var app = angular.module("myTmoApppdl", []).run(function () {
app.service('populatePageObjsService', function () {
var self = this;
self.populatePage = function (digitalData) {
var dataPageObject = document.getElementById('metaJson').getAttribute("data-pageObject");
var jsonPageObject = JSON.parse(dataPageObject);
for (var key in jsonPageObject.page.pageInfo) {
var value = jsonPageObject.page.pageInfo[key];
if (digitalData.page.pageInfo.hasOwnProperty(key)) {
digitalData.page.pageInfo[key] = value;
}
}
console.log("Page data populated successfully: ", digitalData.page.pageInfo);
};
});
});
You can call your service method in .run() block
var app = angular.module("myTmoApppdl", []);
app.run(function(populatePageObjsService){ // inject your service here
//use your service here
});
app.service('populatePageObjsService', function() {
// your service code here
});
With run module
Simple example
var app = angular.module("myTmoApppdl", [])
.run(function(populatePageObjsService) {
populatePageObjsService.init();
})
.service('populatePageObjsService', function() {
var self = this;
self.init = function() {
alert("run");
};
});
Plunker
Since an AngularJS service is singleton, you can be sure that your function will only be executed once, but you have to bear in mind that it is also lazily instantiated - Angular only instantiates a service when an application component depends on it - source.
With this in mind, if a service is somehow self-reliable (for example, fetching the user's country via an API call - since this can be executed only once at the start of the app and it's unlikely for the data to change), besides the usual service bindings, you can also put logic in there.
I've edited your code to showcase this approach.
angular
.module("myTmoApppdl", [])
// populatePageObjsService needs to be injected somewhere otherwise it won't get instantiated
.service('populatePageObjsService', function() {
//////////////
// Bindings //
//////////////
var self = this;
//digitalData is a global object
self.populatePage = function(digitalData) {
var dataPageObject = document.getElementById('metaJson').getAttribute("data-pageObject");
var jsonPageObject = JSON.parse(dataPageObject);
for (var key in jsonPageObject.page.pageInfo) {
var value = jsonPageObject.page.pageInfo[key];
if (digitalData.page.pageInfo.hasOwnProperty(key)) {
digitalData.page.pageInfo[key] = value;
}
}
console.log("Page data populated successfully: ", digitalData.page.pageInfo);
};
///////////////
// Run Block //
///////////////
// Calling the desired function.
self.populatePage(digitalData);
});
angular.element(document).ready(function () {
// your code here
});

using revealling moduler pattern for complex in javascript

I have a very complex class so i decided to break into sub modules and trying to use revealing modules pattern.
I have main class and decided to divide into smaller container function. but in current scenario
But i am not able to access any internal function from outside i.e callSearchResultWithCallBack using searchFinder.Search.callSearchResultWithCallBack(). which pattern should i use to keep this code clean as well have control to call internal function in sub module.
Thanks
var searchFinder;
function SearchFinder() {
me = this;
this.searchResult = null;
this.init = function() {
declareControls();
createAccordian();
addEvents();
fillControls();
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
me.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
}
this.Search = function() {
var url = '';
var searchCriteria = {};
validateAndCreateCriteria();
callSearchResultWithCallBack();
function validateAndCreateCriteria() {
function validateAandGetCategory() {
if (SearchValidation.ValidateZipCode(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
} else if (SearchValidation.ValidateCityState(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
}
}
}
// need to access it outsite
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
}
}
jQuery(function() {
searchFinder = new SearchFinder();
searchFinder.init();
searchFinder.Search.callSearchResultWithCallBack();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
This code has multiple issues, first I will address the fact that for example declareControls is not executing. First declare the function than execute!
this.init = function() {
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
this.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
declareControls();
//createAccordian(); //not defined
addEvents();
fillControls();
}
Now let's look at others problems that will arise.
the me object referring to this is in the scope of searchFinder and does not refer to the same this in the instance of searchFinder.
function jQuery can be replaced by the commonly used $.
searchFinder.Search.callSearchResultWithCallBack() this is never going to work. Since the Search function is an object and callSearchResultWithCallBack isn't a property of this function.
Solution; make it part of the prototype of Search.
Steps:
Move callSearchResultWithCallBack outside the search function.
Add prototype to Search function
Call function via prototype.
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
this.Search.prototype.callSearchResultWithCallBack = callSearchResultWithCallBack;
If you want to fire this function outside of search use this:
searchFinder.Search.prototype.callSearchResultWithCallBack();
Please remember that callSearchResultWithCallBack will throw an error because searchCriteria is undefined.
This fixes your problems for now, but this code has to be revised thoroughly. But this should get you started. http://ejohn.org/blog/simple-javascript-inheritance/

trying to use a closure with parameters as a callback

I have a library function that I'm calling from a method. It takes a callback with one parameter that I would like to be another method from the same object. I can't seem to get the syntax right. Here's what I've got:
myOriginalObject.login = function() {
// inside a method
var obj = this;
var closure = function(token) { return function() { obj._login2(token); } }
$window.gapi.auth.authorize({"client_id": this.clientId,
"immediate":false,
"response_type":"token",
"scope":this.scopes}, closure );
// .. some more code and method ends
}
myOriginalObject._login2 = function(authResult)
{
// .. I can't get this function called by the gapi library
}
P.S. sorry if this post isn't done properly (still learning) thanks!!!
You're passing a reference to the closure function to authorize, but I think you want to call it and pass the reference to the function it creates. So:
// `token` argument here ------------------v
var closure = function() { return function(token) { obj._login2(token); } }
// not here------------^
and
$window.gapi.auth.authorize({"client_id": this.clientId,
"immediate":false,
"response_type":"token",
"scope":this.scopes}, closure() );
// Call it -----------------------------------------------^^
You may not need the closure function at all, but it's hard to tell without knowing more about the surrounding code. But this may well be all you need:
$window.gapi.auth.authorize({"client_id": this.clientId,
"immediate":false,
"response_type":"token",
"scope":this.scopes}, function(token) {
obj._login2(token);
});
Side note: Since myOriginalObject is a singleton, you don't need the var obj = this;, you can just use the symbol myOriginalObject directly:
$window.gapi.auth.authorize({"client_id": this.clientId,
"immediate":false,
"response_type":"token",
"scope":this.scopes}, function(token) {
myOriginalObject._login2(token);
});
This line:
var closure = function(token) { return function() { obj._login2(token); } }
will return a function, i.e. the return value of closure() is a function.
One solution:
change
var closure = function(token) { return function() { obj._login2(token); } }
to
var closure = function(token) { obj._login2(token); }

I wanted to make a javascript library function is not working

I wanted to call the run function that should call the other and action will be done on the base of element_id
NGL = {}
NGL.SceneBuilder = function() {
var yamlFile = 'http://example.com/main.yaml'
var parseYaml = function() {
}
var buildScene = function() {
// other code
simulationStarted(element_id);
}
return {
run: function(element_id) {
parseYaml();
buildScene(element_id);
}
}
}
NGL.SceneBuilder.run('#someid');
You're not executing your factory so NGL.SceneBuilder is a function, not an object having the run property. Call the function :
NGL.SceneBuilder = (function() {
...
})(); // <<===
Note also that you forget to declare the element_id parameter in buildScene but maybe is it just for the question.

angular watch object not in scope

I have a service in which values can change from outside Angular:
angularApp.service('WebSocketService', function() {
var serviceAlarms = [];
var iteration = 0;
this.renderMessages = function(alarms, socket) {
if (! angular.equals(serviceAlarms, alarms)) {
serviceAlarms = alarms;
iteration++;
}
};
this.getAlarms = function () {
return serviceAlarms;
};
this.iteration = function () {
return iteration;
};
this.socket = initSocketIO(this);
});
The initSocketIO function makes callbacks to this services renderMessages() function and serviceAlarms variable gets changed on a steady basis.
Now i am trying to watch for changes in this service like so:
controllers.controller('overviewController', ['$scope', 'WebSocketService', function ($scope, WebSocketService) {
$scope.$watch(
function () {
return WebSocketService.iteration();
},
function(newValue, oldValue) {
$scope.alarms = WebSocketService.getAlarms();
},
true
);
}]);
to no avail. The second function provided to $watch never gets executed except on controller initialization.
I have tried with and without true as third parameter.
You should use $rootScope.$watch (not $scope.$watch)
I ended up using the solution below since $watch didn't work as excpected.
I refactored the solution to use $rootScope in combination with:
angularApp.run(['$rootScope', function($rootScope){
$rootScope.socket = {};
$rootScope.socket.alarms = [];
$rootScope.socket.faults = [];
$rootScope.socket.renderErrors = function(faults, socket) {
var faultArray = [];
angular.forEach(faults, function(error) {
error.value ? faultArray.push(error) : null;
});
if (! angular.equals($rootScope.socket.faults, faultArray)) {
$rootScope.socket.faults = faultArray;
$rootScope.apply();
}
};
$rootScope.socket.renderMessages = function(alarms, socket) {
if (! angular.equals($rootScope.socket.alarms, alarms)) {
$rootScope.socket.alarms = alarms;
$rootScope.$apply();
}
};
$rootScope.socket.socket = initSocketIO($rootScope.socket);
}]);
Now i have my socket-updated-model in all scopes to use freely in controllers and views.
Controller example:
$scope.acknowledgeAlarm = function(alarm) {
$scope.socket.socket.emit('acknowledgeAlarm', {
hash:alarm.icon.hash,
id:alarm.id
});
};
View example:
<div ng-repeat="alarm in socket.alarms">
{{alarm.name}} {{alarm.icon.progress}}
</div>

Categories

Resources