How to change controller variable in service angular? - javascript

This's my service. I've got variable isPolygonDrawingEnded there.
angular
.module('gillie.clients.app')
.service('mapDrawingService', mapDrawingService);
mapDrawingService.$inject = ['$ngBootbox', '$translate', 'fitPolygonService', 'mapCommonService'];
function mapDrawingService($ngBootbox, $translate, fitPolygonService, mapCommonService) {
var self = this;
var map;
var polygonFeatures;
var stopDrawingAction;
var isPolygonDrawingEnded = false;
var isDrawingMode = true;
self.startNewPolygonDrawing = function (afterDrowed) {
fitPolygonService.suggestPoint(isDrawingMode);
var modify = createModifyInteractionToPolygonFeatures();
var draw = createDrawInteraction();
attachDrawEvents(draw, afterDrowed);
map.addInteraction(draw);
stopDrawingAction = function() {
map.removeInteraction(draw);
map.removeInteraction(modify);
};
};
var attachDrawEvents = function (draw, afterDrowed) {
draw.on('drawend', function (e) {
e.preventDefault();
afterDrowed();
isPolygonDrawingEnded = true;
if (fitPolygonService.isPolygonsExist()) {
var geometry = e.feature.getGeometry();
e.feature.setGeometry(fitPolygonService.fitPolygon(geometry));
}
});
}
This is my controller. Here I need to change $scope.showCountButton when mapDrawingService.isPolygonDrawingEnded == true. So how can I know that value in service is changed ?
angular
.module('gillie.clients.app')
.controller('regionController', regionController);
regionController.$inject = ['$q', '$filter', '$scope', '$ngBootbox', '$translate', 'regionService', 'mapService', 'mapDrawingService', 'modalService', 'regionCommonService', 'alertService', 'nominatimCommonService', 'populationService', 'provinceCommonService', 'provinceService', 'rx'];
function regionController($q, $filter, $scope, $ngBootbox, $translate, regionService, mapService, mapDrawingService, modalService, regionCommonService, alertService, nominatimCommonService, populationService, provinceCommonService, provinceService, rx) {
$scope.showCountButton = false;
$scope.startRegionSelection = function (region) {
$scope.isSavingAvailable = true;
$scope.showCountButton = false;
if (currentEditingRegion && region && currentEditingRegion.Id === region.Id) {
return;
}
if(region)
mapService.clearRegion(region);
if (currentEditingRegion && !region) {
mapDrawingService.continuePolygonDrawing();
return;
}
if (region) {
mapDrawingService.stopPolygonDrawing();
mapDrawingService.clearMap();
currentEditingRegion = region;
mapDrawingService.startExistPolygonDrawing(region.Name, region.CoordinatesJson);
return;
}
mapDrawingService.startNewPolygonDrawing(function () {
$scope.showCountButton = true
});
};
When I use mapDrawingService.startNewPolygonDrawing function - the value of showCountButton changes but view doesn't. $scope.$apply produces this exception:
[$rootScope:inprog] $digest already in progress

When you are passing the callback function it is no longer in the scope of the controller which is why the view is not updating. You can use promises instead since you are asynchronous draw event.
Service
mapDrawingService.$inject = ['$q', '$ngBootbox', '$translate', 'fitPolygonService', 'mapCommonService'];
function mapDrawingService($q, $ngBootbox, $translate, fitPolygonService, mapCommonService) {
var self = this;
var map;
var polygonFeatures;
var stopDrawingAction;
var isPolygonDrawingEnded = false;
var isDrawingMode = true;
self.startNewPolygonDrawing = function() {
fitPolygonService.suggestPoint(isDrawingMode);
var modify = createModifyInteractionToPolygonFeatures();
var draw = createDrawInteraction();
var promiseObj = attachDrawEvents(draw);
map.addInteraction(draw);
stopDrawingAction = function() {
map.removeInteraction(draw);
map.removeInteraction(modify);
};
return promiseObj;
};
var attachDrawEvents = function(draw) {
return $q(function(resolve, reject) {
draw.on('drawend', function(e) {
e.preventDefault();
if (fitPolygonService.isPolygonsExist()) {
var geometry = e.feature.getGeometry();
e.feature.setGeometry(fitPolygonService.fitPolygon(geometry));
}
resolve();
});
});
}
Controller
mapDrawingService.startNewPolygonDrawing().then(function() {
$scope.showCountButton = true
});

Related

How to declare a function in angularjs

I have a function and i did it in this way
JS :
function updateInstitution (isValid) {alert('hi')
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.form.institutionForm');
return false;
}
var data = JSON.stringify(vm.institution);
httpService.put('institutions/' + vm.institution_id, data).then(function (results) {
if (results && results.data && results.data.details) {
vm.institution = results.data.details;
formInstitutionData('profile');
commonService.showNotification('success', 'Institution Details updated successfully!');
$('#institutionModal').modal('hide');
}
});
}
}
vm.updateInstitution = updateInstitution;
Html :
<button type="button" class="btn btn-blue" ng-click="vm.updateInstitution(vm.form.institutionForm.$valid)" ng-bind="field.saveText"></button>
But i am getting the error as
updateInstitution is not defined
Can anyone please suggest help.Thanks.
JS :
(function () {
'use strict';
// Institutions controller
angular
.module('institutions')
.controller('InstitutionsController', InstitutionsController);
InstitutionsController.$inject = ['$scope', '$state', '$window', '$timeout', 'httpService', 'Authentication', 'commonService'];
function active() {
httpService.get('institutions/' + vm.institution_id).then(function (results) {
if (results && results.data && results.data.details) {
vm.institutionCopyData = angular.copy(results.data.details);
formInstitutionData('all');
}
});
}
$scope.editInstitutionModal = function (type) {
$scope.field = {};
$scope.showInstitutionModal = false;
if (type === 'basicedit') {
$scope.field.field_type = 'edit-institution.form.client';
$scope.field.formName = 'Edit institution (' + vm.institutionObj.name + ')';
$scope.field.saveText = 'Update';
}
if(type === 'general'){
$scope.field.field_type = 'add-general.form.client';
$scope.field.formName = 'General Info';
$scope.field.saveText = 'Save';
}
$timeout(function () {
$scope.showInstitutionModal = true;
$('#institutionModal').modal('show');
$scope.$apply();
}, 10);
};
function updateInstitution (isValid) {alert('hi')
if (!isValid) {
$scope.$broadcast('show-errors-check-validity', 'vm.form.institutionForm');
return false;
}
var data = JSON.stringify(vm.institution);
httpService.put('institutions/' + vm.institution_id, data).then(function (results) {
if (results && results.data && results.data.details) {
vm.institution = results.data.details;
formInstitutionData('profile');
commonService.showNotification('success', 'Institution Details updated successfully!');
$('#institutionModal').modal('hide');
}
});
}
}
}
}());
But i am getting the error as
updateInstitution is not defined
Can anyone please suggest help.Thanks.
But i am getting the error as
updateInstitution is not defined
Can anyone please suggest help.Thanks.
You should declare the following in your controller:
var vm = this;
vm.updateInstitution = updateInstitution;
you use $scope.updateInstitution instead of function updateInstitution() , because communication bridge between html and controller is $scope,
or for use vm.function you defined $scope.vm
$scope.updateInstitution = function(){
//Your code
}

infinite scroll in angular directive

I coded the below directive for infinite scroll, my problem which I couldn't figure out why it just fire once when the directive is loaded, I need your advice on how to make my list infinite-scroll.
I'm using it to get data remotely and each time i'm calling it I add to the counter 25, so each time it would return more data.
Thanx,
angular.module('MyApp')
.controller('InboxCtrl', function($scope, InboxFactory) {
var counter = 0;
$scope.loadData = function() {
var promise = InboxFactory.getEvents(counter);
promise.then(function(result) {
$scope.events = result;
});
counter += 25;
};
});
angular.module('MyApp')
.factory('InboxFactory', function($http, $q) {
// Service logic
var defered = $q.defer();
function getUrl(count) {
return "api/inbox/get?request={'what':'Search','criteria':'inbox','criteriaId':null,'startTime':null,'endTime':null,'offset':" + count + ",'limit':25,'order':'event_time','direction':'DESC','source':''}";
}
function extract(result) {
return result.data.data;
}
// Public API here
return {
getEvents: function(count) {
$http.get(getUrl(count)).then(
function(result) {
defered.resolve(extract(result))
}, function(err) {
defered.reject(err);
}
);
return defered.promise;
}
};
});
angular.module('MyApp')
.directive('infiniteScroll', ['$timeout',
function(timeout) {
return {
link: function(scope, element, attr) {
var
lengthThreshold = attr.scrollThreshold || 50,
timeThreshold = attr.timeThreshold || 400,
handler = scope.$eval(attr.infiniteScroll),
promise = null,
lastRemaining = 9999;
lengthThreshold = parseInt(lengthThreshold, 10);
timeThreshold = parseInt(timeThreshold, 10);
if (!handler || !components.isFunction(handler)) {
handler = components.noop;
}
element.bind('scroll', function() {
var
remaining = element[0].scrollHeight - (element[0].clientHeight + element[0].scrollTop);
//if we have reached the threshold and we scroll down
if (remaining < lengthThreshold && (remaining - lastRemaining) < 0) {
//if there is already a timer running which has no expired yet we have to cancel it and restart the timer
if (promise !== null) {
timeout.cancel(promise);
}
promise = timeout(function() {
handler();
promise = null;
}, timeThreshold);
}
lastRemaining = remaining;
});
}
};
}
]);
<ul class="inbox-list" infinite-scroll="loadData()">
<li class="clearfix" ng-repeat="event in events">{{event}}</li>
</ul>
I Made some changes the more important is the use of ng-transclude and the creation of a new scope for the directive to pass the method and the parameters. You can have a look at the jsbind. Of course the data are hard coded so i could fake the behaviour.
<ul class="inbox-list" my-infinite-scroll composite-method="loadData()">

angular websocket factory

I have websocket service that works great when page is loaded. However, if connection is lost, and the service is trying to reconnect I am getting an error: "Uncaught ReferenceError: Service is not defined". Once I manually refresh page, service is working again. How can I reconnect without page refreshing? The app must reestablish that connection without any user involvement. This is my first angular app, so I am still in the process of learning the framework. Thank you.
angular.module('proApp').factory('webSocketService',
['$q', '$rootScope', function($q, $rootScope) {
var timeout = 2000;
var clearTimer = -1;
var port = '8081';
var server = '127.0.0.1';
var socket;
var host;
var Service = {};
function getSocketState() {
return (socket != null) ? socket.readyState : 0;
}
function onMessage(e) {
//console.log(e.data);
Service.message = JSON.parse(e.data);
$rootScope.$apply(function() {
Service.send();
});
}
//allows data to be used in controller
Service.send = function() {
$rootScope.$broadcast('broadcast');
};
function onError() {
clearInterval(clearTimer);
socket.onclose = function() {
};
clearTimer = setInterval("Service.getData()", timeout);
}
function onClose() {
clearInterval(clearTimer);
clearTimer = setInterval("Service.getData()", timeout);
}
function onOpen() {
clearInterval(clearTimer);
console.log("open" + getSocketState());
}
Service.getData = function() {
if ("WebSocket" in window) {
if (getSocketState() === 1) {
socket.onopen = onOpen;
clearInterval(clearTimer);
console.log(getSocketState());
} else {
try {
host = "ws://" + server + ":" + port + '';
socket = new WebSocket(host);
socket.onopen = onOpen;
socket.onmessage = function(e) {
onMessage(e);
};
socket.onerror = onError;
socket.onclose = onClose;
} catch (exeption) {
console.log(exeption);
}
}
}
};
// Public API here
return Service;
}]);
You have to change the use of setInterval to be like this:
clearTimer = setInterval(function () {
Service.getData();
}, timeout);
or just this:
clearTimer = setInterval(Service.getData, timeout);
This is the code I use, it can:
reconnect if connection is lost.
queue items while disconnected and send them on re-connection.
regular subscribing using the "listen" method.
"listenOnce" for an event once with a promise, after that the subscription is removed. Ideal for request/response using a correlationId
$rootScope.websocketAvailable indicates when the connection is available.
$rootScope.queuedMessages indicates when there are pending messages to be sent.
It is still part of a project in development, but I guess you can get the idea:
.service('$connection', ["$q", "$timeout", "websocketUrl", "$rootScope", function ($q, $timeout, websocketUrl, $rootScope) {
var connection = function () {
var me = {};
var listeners = [];
var oneListeners = [];
me.isConnected = false;
oneListeners.removeOne = function (listener) {
var index = oneListeners.indexOf(listener);
if(index!=-1)
oneListeners.splice(index, 1);
};
var correlationId = 0;
me.nextCorrelationId = function () {
return correlationId++;
};
$rootScope.queuedMessages = [];
me.listen = function (predicate, handler) {
listeners.push({ p: predicate, h: handler });
};
me.listenOnce = function (predicate, timeout) {
var deferred = $q.defer();
deferred.done = false;
var listener = { d: deferred, p: predicate };
oneListeners.push(listener);
if (timeout) {
$timeout(function () {
if (!deferred.done)
deferred.reject('timeout');
oneListeners.removeOne(listener);
}, timeout);
}
var promise = deferred.promise;
promise.then(function (data) {
deferred.done = true;
});
return promise;
};
var onopen = function () {
console.log('onopen');
$rootScope.websocketAvailable = true;
me.isConnected = true;
$rootScope.$$phase || $rootScope.$apply();
if ($rootScope.queuedMessages) {
for (var i = 0; i < $rootScope.queuedMessages.length; i++) {
ws.send(JSON.stringify($rootScope.queuedMessages[i]));
}
$rootScope.queuedMessages = null;
$rootScope.$$phase || $rootScope.$apply();
}
};
var onclose = function () {
console.log('onclose');
me.isConnected = false;
$rootScope.websocketAvailable = false;
$rootScope.$$phase || $rootScope.$apply();
$rootScope.queuedMessages = $rootScope.queuedMessages || [];
setTimeout(function () {
ws = connect();
}, 5000);
};
var onmessage = function (msg) {
console.log('onmessage');
var obj = JSON.parse(msg.data);
for (var i = 0; i < listeners.length; i++) {
var listener = listeners[i];
if (listener.p(obj))
listener.h(obj);
}
var remove = [];
for (var i = 0; i < oneListeners.length; i++) {
var listener = oneListeners[i];
if (listener.p(obj)) {
var o = obj;
listener.d.resolve(o);
remove.push(listener);
}
}
for (var i = 0; i < remove.length; i++) {
oneListeners.removeOne(remove[i]);
}
};
var onerror = function () {
console.log('onerror');
};
me.send = function (obj) {
if ($rootScope.queuedMessages)
$rootScope.queuedMessages.push(obj);
else
ws.send(JSON.stringify(obj));
}
var setHandlers = function (w) {
w.onopen = onopen;
w.onclose = onclose;
w.onmessage = onmessage;
w.onerror = onerror;
};
var connect = function () {
console.log('connecting...');
var w = new WebSocket(websocketUrl);
setHandlers(w);
return w;
}
var ws = connect();
return me;
};
return connection();
}])

Variable coming back undefined into the same scope in AngularJS

Given the following code, I'm finding that once the loadDetails function (the last one) is being triggered, the ID variable comes back undefined, as on the other functions is coming back correctly.
Did I miss something?
function Ctrl($scope, $http) {
var search = function(name) {
if (name) {
$http.get('http://api.discogs.com/database/search?type=artist&q='+ name +'&page=1&per_page=7', {ignoreLoadingBar: true}).
success(function(data3) {
$scope.clicked = false;
$scope.results = data3.results;
});
}
$scope.reset = function () {
$scope.sliding = false;
$scope.name = undefined;
}
}
$scope.$watch('name', search, true);
$scope.getDetails = function (id) {
$http.get('http://api.discogs.com/artists/' + id).
success(function(data) {
$scope.artist = data;
});
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=1&per_page=8').
success(function(data2) {
$scope.releases = data2.releases;
});
$scope.$watch(function() {
return $scope.artist;
}, function() {
var pos = $scope.artist.name.toLowerCase().indexOf(', the');
if (pos != -1) {
$scope.artist.name = 'The ' + $scope.artist.name.slice(0, pos);
}
});
var _page = 0;
$scope.releases = [];
$scope.loadDetails = function(id) {
_page++;
console.log(_page);
$http.get('http://api.discogs.com/artists/' + id + '/releases?page=' + _page + '&per_page=12').then(function(data2) {
$scope.releases = data2.releases;
});
};
$scope.clicked = true;
$scope.sliding = true;
}
EDIT: Here's my view code:
<div class="infinite" infinite-scroll="loadDetails(artist.id)">
<div class="col-xs-3 col-md-3 release" ng-controller="ImageCtrl" release="release" ng-repeat="release in releases | filter:album | filter:year" the-directive position="{{ $index + 1 }}" last="{{ $last }}">
<img class="img-responsive" ng-src="{{image}}"/> {{release.title | characters:45}}
</div>
<div style='clear: both;'></div>
</div>
And the ng-Infinite-Scroll script that triggers the function when the containing div reaches the bottom:
/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */
var mod;
mod = angular.module('infinite-scroll', []);
mod.directive('infiniteScroll', [
'$rootScope', '$window', '$timeout', function($rootScope, $window, $timeout) {
return {
link: function(scope, elem, attrs) {
var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
$window = angular.element($window);
scrollDistance = 0;
if (attrs.infiniteScrollDistance != null) {
scope.$watch(attrs.infiniteScrollDistance, function(value) {
return scrollDistance = parseInt(value, 10);
});
}
scrollEnabled = true;
checkWhenEnabled = false;
if (attrs.infiniteScrollDisabled != null) {
scope.$watch(attrs.infiniteScrollDisabled, function(value) {
scrollEnabled = !value;
if (scrollEnabled && checkWhenEnabled) {
checkWhenEnabled = false;
return handler();
}
});
}
handler = function() {
var elementBottom, remaining, shouldScroll, windowBottom;
windowBottom = $window.height() + $window.scrollTop();
elementBottom = elem.offset().top + elem.height();
remaining = elementBottom - windowBottom;
shouldScroll = remaining <= $window.height() * scrollDistance;
if (shouldScroll && scrollEnabled) {
if ($rootScope.$$phase) {
return scope.$eval(attrs.infiniteScroll);
} else {
return scope.$apply(attrs.infiniteScroll);
}
} else if (shouldScroll) {
return checkWhenEnabled = true;
}
};
$window.on('scroll', handler);
scope.$on('$destroy', function() {
return $window.off('scroll', handler);
});
return $timeout((function() {
if (attrs.infiniteScrollImmediateCheck) {
if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
return handler();
}
} else {
return handler();
}
}), 0);
}
};
}
]);
rSo from what I read I understand you problem as in loadDetails() the id parameter is undefined. Where is loadDetails() called from? I assume its being called from the view. Are you passing this param in when it is being called? For ex:
<button ng-click="loadDetails('myId')">Load Details</button>
I would say your issue is you are not passing the param to this function. It would be helpful if you posted the view associated with this controller.

getting TypeError: Cannot call method 'then' of undefined in angularjs controller

I keep getting the error - TypeError: Cannot call method 'then' of undefined when i call a method (database.readOnlyStock()) in my factory. also what i find a little ackward is that the function then does run accordingly because i see the console.log messages.
here is the factory code:
stocks.factory('database', ['$resource', '$http', '$q', function($resource, $http, $q) {
var dataMethods = {
createConnection: function() {
/*moved to onload below */
},
addStock: function(stock, nameofcompany) {
var _this = this;
console.log("About to add stock");
//Get a transaction
//default for OS list is all, default for type is read
var transaction = this.db.transaction(["portfolio"],"readwrite");
//Ask for the objectStore
var store = transaction.objectStore("portfolio");
//Define a person
var stockTemplate = {
company_name: nameofcompany,
name:stock,
created:new Date()
}
//Perform the add
var request = store.add(stockTemplate);
request.onerror = function(e) {
console.log("failed to add stock to portflio",e.target.error.name);
//some type of error handler
}
request.onsuccess = function(e) {
console.log("successfully added stock to portfolio");
//console.log(store);
//_this.readOnlyStock();
}
},
readOnlyStock: function() {
var deferred = $q.defer();
var transaction = this.db.transaction(["portfolio"],"readonly");
var store = transaction.objectStore("portfolio");
// var cursorRequest = store.openCursor();
var arrayOfStocks = [];
var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function(e) {
var cursor = e.target.result;
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
}
else{
console.log(arrayOfStocks);
console.log('done!');
deferred.resolve(arrayOfStocks);
return deferred.promise;
//return arrayOfStocks;
}
}
cursorRequest.onerror = function(){
console.log('could not fetch data');
}
},
deleteStock: function() {}
}
//return dataMethods;
if (window.indexedDB) {
console.log('indexeddb is supported');
var openRequest = indexedDB.open("users_stocks", 4);
openRequest.onupgradeneeded = function(e) {
var thisDB = e.target.result;
if (!thisDB.objectStoreNames.contains("portfolio")) {
console.log('created object store');
thisDB.createObjectStore("portfolio", {
autoIncrement: true
});
}
}
openRequest.onsuccess = function(e) {
console.log('connection opened');
dataMethods.db = e.target.result
}
openRequest.onerror = function(e) {
console.log('could not open connection');
}
return dataMethods;
}
else {
console.log('indexedDB not supported');
}
}]);
and then here is my controller code:
stocks.controller('portfolio', ['$scope', '$http', 'stockData', 'database', function portfolio($scope, $http, stockData, database) {
$scope.getAllStocks = function(){
console.log('running getll stocks');
database.readOnlyStock().then(function(result) {
console.log('done');
$scope.allstuff = result;
}, function(){
console.log('no');
});
}
}]);
not sure where the issue is.
You need to return the promise from the readOnluStock method, not from the success handler within it
readOnlyStock: function () {
var deferred = $q.defer();
var transaction = this.db.transaction(["portfolio"], "readonly");
var store = transaction.objectStore("portfolio");
// var cursorRequest = store.openCursor();
var arrayOfStocks = [];
var keyRange = IDBKeyRange.lowerBound(0);
var cursorRequest = store.openCursor(keyRange);
cursorRequest.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
arrayOfStocks.push(cursor.value);
cursor.
continue ();
} else {
console.log(arrayOfStocks);
console.log('done!');
deferred.resolve(arrayOfStocks);
//return arrayOfStocks;
}
}
cursorRequest.onerror = function () {
console.log('could not fetch data');
}
// the return should be here
return deferred.promise;
},
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
}
when the control reaches this part, it doesnt return anything explicitly. It means that by default undefined will be returned by javascript. So, you are trying to call then on undefined. You might want to change this to
if(cursor){
arrayOfStocks.push(cursor.value);
cursor.continue();
return deferred.promise;
}

Categories