I have a $stateChangeStart event trigger whenever user navigate between the templates, so in below code when user change a state i am deleting $scope.filename that is working as expected but when i go back to that page its throwing a exception and i lose socket.io connection because $scope.filename value is still there that is executing if statement. How can i destroy $scope value in this case ?
ctrl.js
angular.module('loggingApp').controller('DitCtrl', function($scope, $rootScope, DitFactory, FileSaver, Blob, socket, $uibModal, searchFactory) {
'use strict';
$scope.event = [];
$scope.disabledRecBtn = false;
$scope.disabledStopBtn = true;
$scope.showMessage = false;
var totalCurrentBytes = [];
$scope.curVal = 4000;
$scope.maxVal = 37737;
//ENDS HERE
var sendMessageFlag = false;
// Delete File method
function deleteFile(filename) {
DitFactory.getFile(filename).then(function(response, $window) {
console.log('data for download', response);
var data = JSON.stringify(response.data);
var blob = new Blob([data], {
type: 'text/plain;charset=utf-8'
});
FileSaver.saveAs(blob, 'server.log');
socket.emit('stopRecording', $scope.filename);
});
}
socket.on('ditConsumer', function(data) {
var obj = {
file: $scope.filename,
data: data
}
$scope.event.push(data);
jsonToArray();
socket.emit('messageToFile', obj);
if (sendMessageFlag === true) {
return sendMessageToFile(obj);
}
});
function sendMessageToFile(data) {
if (data.file) {
socket.emit('startrecording', data);
$scope.disabledRecBtn = true;
$scope.disabledStopBtn = false;
$scope.showMessage = true;
}
}
$scope.stopLogs = function() {
sendMessageFlag = false;
$scope.modalInstance = $uibModal.open({
templateUrl: '/web/global/modal.html',
controller: 'ModalController'
});
};
$rootScope.$on('downloadFile', function(s, data) {
deleteFile($scope.filename);
$scope.disabledRecBtn = false;
$scope.disabledStopBtn = true;
$scope.showMessage = false;
});
$rootScope.$on('onCancelDelete', function() {
if ($scope.filename) {
console.log('oncanceldelete function');
socket.emit('stopRecording', $scope.filename);
$scope.disabledRecBtn = false;
$scope.disabledStopBtn = true;
$scope.showMessage = false;
}
});
$scope.recordLogs = function() {
socket.emit('createlogfile');
socket.on('filename', function(filename) {
console.log('filename from sever', filename);
$scope.filename = filename;
sendMessageFlag = true;
$scope.disabledRecBtn = true;
$scope.disabledStopBtn = false;
$scope.showMessage = true;
});
}
//Search logs code here
$scope.searchLogs = function() {
$scope.modalInstance = $uibModal.open({
templateUrl: '/view/modals/searchModal.html',
controller: 'SearchController'
});
searchFactory.setDitLogs($scope.event);
}
$scope.serverFiles = function() {
$scope.modalInstance = $uibModal.open({
templateUrl: '/view/modals/serverModal.html',
controller: 'ServerFilesCtrl'
})
}
$rootScope.$on('$stateChangeStart',
function(event, toState, toParams, fromState, fromParams){
if($scope.filename) {
console.log($scope.filename);
console.log('STATE CHANGED');
console.log('destroy on close');
socket.emit('stopRecording', $scope.filename);
sendMessageFlag = false;
$scope.filename = null;
}
})
});
All the scopes are destroyed when a routing is done. That is the feature that ui- router comes with. If you want to manually specify it for a certain purpose you can always use $scope.$destroy for certain controllers.
when i go back to state all methods are invoking twice e.g $scope.recordLogs printing console.log('filename from sever', filename);
The console.log is part of the handler function that has been given to the socket service. Even though the $scope has been destroyed, the socket.on handler function has been saved by the socket service.
$scope.recordLogs = function() {
socket.emit('createlogfile');
//PROBLEM
//event handler function retained by socket service
socket.on('filename', function(filename) {
console.log('filename from sever', filename);
$scope.filename = filename;
sendMessageFlag = true;
$scope.disabledRecBtn = true;
$scope.disabledStopBtn = false;
$scope.showMessage = true;
});
}
To avoid duplicating event handlers when a user navigates back and forth between routes use socket.forward:
angular.module('myMod', ['btford.socket-io']).
controller('MyCtrl', function ($scope, socket) {
socket.forward('someEvent', $scope);
$scope.$on('socket:someEvent', function (ev, data) {
$scope.theData = data;
});
});
By using socket.forward, the socket service will unregister the handler when the $scope gets destroyed.
For more information, see angular-socket-io API Reference - socket.forward
Related
I have a Sharepoint list I'm trying to get items from and populate in an Angular app. When the page loads, nothing is loaded, if I click off the page and click back the data shows up. How can I get the items to load sooner, like before the page is initially loaded?
Here's my page controller.
app.controller("organizationsCtrl", ["$scope", "$rootScope", "$location", "$routeParams", "spService", "dataService",
function ($scope, $rootScope, $location, $routeParams, spService, dataService) {
$scope.editing = false;
$scope.column = "id";
$scope.reverse = false;
$scope.organizations = dataService.getOrganizations();
$scope.navToAdd = function() {
$location.path("/organizations/add");
}
$scope.navToEdit = function(index) {
$location.path("/organizations/" + index);
};
$scope.sortColumn = function(col) {
$scope.column = col;
if($scope.reverse) {
$scope.reverse = false;
//$scope.reverseclass = 'arrow-up';
} else {
$scope.reverse = true;
//$scope.reverseclass = 'arrow-down';
}
};
}
]);
Here is my service.
app.service('dataService', ['$rootScope', 'spService', function ($rootScope, spService) {
var svc = {};
var organizations = {};
svc.getOrganizations = function() {
spService.getRecords("Organizations", "?$select=ID,Title").then(function (result) {
organizations = result;
});
return organizations;
}
return svc;
}]);
I want to make chat app. So when I send message you can hear pop. So i have two directives, one for my messages and other for simulation. Simulation is working just one time and then stop. I cant get objects from $scope.data to directive myDirective. I really tried almost everything. Is there any solution?
var app = angular.module('myApp', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
//angular-ui-router
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home',{
url:'/',
views:{
'':{
templateUrl:'../ChatApp/views/chatapp.html'
}
}
})
.state('login',{
url:'/login',
templateUrl:'../ChatApp/views/login.html',
controller: 'LoginController'
});
});
app.controller('MessageController', function($scope,$filter, $http,$state,$timeout,$compile,$interval) {
$scope.randomNumber = Math.floor(Math.random()*(2-0+1)+0);
$scope.data = [];
$scope.name = localStorage.getItem('Name');
console.log(localStorage);
console.log(localStorage.getItem('Name'));
$scope.sendedMessage = "";
$scope.data1 = [$scope.name,$scope.sendedMessage,$scope.date];
//geting data from json
$scope.getData = function () {
$http.get('../ChatApp/data/data.json')
.then(function(response) {
$scope.data =response.data.messages;
console.log($scope.data);
});
};
//logout button
$scope.logout = function () {
localStorage.clear();
console.log(localStorage);
};
//function for rocket button
$scope.sendMessage = function (message) {
$scope.date = new Date();
$scope.date = $filter('date')(new Date(), 'HH:mm:ss');
$scope.message = null;
$scope.sendedMessage = message;
var audio = new Audio('../ChatApp/sounds/videoplayback');
audio.play();
};
//simple autentification
$scope.login = function () {
if(localStorage.getItem('Name') == null){
$state.go('login');
}
};
(function() {
$scope.getData();
$scope.login();
})();
});
app.controller('LoginController', function($scope, $state) {
//simple login
$scope.login = function (name) {
if(name == ""){
alert('Write your name! ');
}
else
{
localStorage.setItem('Name', $scope.name);
$state.go('home');
}
}
});
app.$inject = ['$scope'];
//When you click button rocket, you are adding this to html
app.directive("boxCreator", function($compile){
return{
restrict: 'A',
link: function(scope , element){
if(scope.sendedMessage != undefined && scope.sendedMessage!=null){
element.bind("click", function(e){
var childNode = $compile('<li class="self"><div class="msg"><div class="user">{{:: name}}</div><p>{{:: sendedMessage}}</p><time>{{:: date}}</time></div></li>')(scope);
angular.element( document.querySelector('#chat')).append(childNode);
});
}
//doStuff literally does nothing
scope.doStuff = function(){
alert('hey');
}
}
}
});
app.directive('myDirective', function() {
return {
compile: function(element, attr,$compile) {
var newElement = angular.element('<li class="other"><div class="msg"><div class="user">{{data[randomNumber].name}}</div><p>{{data[randomNumber].message}}</p><time>{{data[randomNumber].date}}</time></div></li>');
element.append(newElement);
var audio = new Audio('../ChatApp/sounds/videoplayback');
audio.play();
return function(scope, element, attr) {
setInterval(function () {
scope.$watch('data', function (data) {
console.log("fff", scope.data);
});
var newElement = angular.element('<li class="other"><div class="msg"><div class="user">{{name}}</div><p>{{scope.data[0].message}}</p><time>{{data[0].date}}</time></div></li>');
element.append(newElement);
var audio = new Audio('../ChatApp/sounds/videoplayback');
audio.play();
},5000);
}
}
}
});
});
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
});
I have this variable that is being controlled by the Factory and to update the Controller but it's not happening.
Here is what I have:
var app = angular.module('plunker', []);
app.controller('AppController', function($scope, AppFactory) {
var vm = this;
$scope.serverStatus = AppFactory.getStatus();
});
app.factory('AppFactory', function($timeout) {
var AppFactory = {};
var vm = this;
vm.serverStatus = true;
// Execute after 2 seconds of page start
$timeout(function() {
AppFactory.setStatus(false);
}, 2000);
AppFactory.setStatus = function(status) {
console.log('Server set to ' + status);
vm.serverStatus = status;
// Getting server status = false
AppFactory.getStatus();
};
AppFactory.getStatus = function() {
console.log('Getting server status: ' + vm.serverStatus);
return vm.serverStatus;
};
return AppFactory;
});
LIVE PLUNKER DEMO: https://plnkr.co/edit/62xGw7Klvbywp9TODWF4?p=preview
Do you think Directives would work better with 2-way-communication between a factory and controller?
Check this edited the plunkr https://plnkr.co/edit/z6tdr5?p=preview
var app = angular.module('plunker', []);
app.controller('AppController', function($scope,$timeout, AppFactory) {
var vm = this;
$timeout(function() {
AppFactory.setStatus(false);
$scope.serverStatus = AppFactory.getStatus();
}, 2000);
$scope.serverStatus = AppFactory.getStatus();
});
app.factory('AppFactory', function($timeout) {
var AppFactory = {};
var serverStatus = true;
// Execute after 2 seconds of page start
return {
getStatus: function () {
//console.log('Getting server status: ' + vm.serverStatus);
return serverStatus;
},
setStatus : function(status) {
var vm = this;
console.log('Server set to ' + status);
serverStatus = status;
// Getting server status = false
vm.getStatus();
}
};
});
Here's a solution that uses events, e.g.:
app.controller('AppController', function($scope, AppFactory) {
var vm = this;
$scope.$on('messageOne', function(event, data){
console.log(data);
$scope.serverStatus = data;
$scope.$apply(); //I think $apply() is not needed here!
});
$scope.serverStatus = AppFactory.getStatus();
});
app.factory('AppFactory', function($timeout, $rootScope) {
var AppFactory = {};
var vm = this;
vm.serverStatus = true;
// Execute after 2 seconds of page start
$timeout(function() {
AppFactory.setStatus(false);
}, 2000);
AppFactory.setStatus = function(status) {
console.log('Server set to ' + status);
vm.serverStatus = status;
// Getting server status = false
//AppFactory.getStatus();
$rootScope.$broadcast('messageOne', status);
};
AppFactory.getStatus = function() {
console.log('Getting server status: ' + vm.serverStatus);
return vm.serverStatus;
};
return AppFactory;
});
https://plnkr.co/edit/pARMnE3Wl0OeJezKuvLT?p=info
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;
}