im using a service that basically popups a box when a user tries to refresh or close the page, and it works fine, but basically i just want to be apply in a specific page, but the problem is that being applied in the rest of the pages.
I tried applying inside of a if statement that includes a specifc state location, but still is being applied in the rest of the app.
Service:
angular.module('farm')
.factory('beforeUnload', function ($rootScope, $window) {
// Events are broadcast outside the Scope Lifecycle
$window.onbeforeunload = function (e) {
var confirmation = {};
var event = $rootScope.$broadcast('onBeforeUnload', confirmation);
if (event.defaultPrevented) {
return confirmation.message;
}
};
$window.onunload = function () {
$rootScope.$broadcast('onUnload');
};
return {};
})
.run(function (beforeUnload) {
// Must invoke the service at least once
});
Controller:
if ($state.includes("app.cal.lab.result")){
$scope.$on('onBeforeUnload', function (e, confirmation) {
confirmation.message = "All data willl be lost.";
e.preventDefault();
});
$scope.$on('onUnload', function (e) {
console.log('leaving page'); // Use 'Preserve Log' option in Console
});
}
Related
I'm communicating an iframe with an angular controller using window.postMessage function https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage#The_dispatched_event
The JS that is inside my iframe is as simple as this.
//Call this function after clicking button
function runOperationFromExternal(operationId){
console.log('Button clicked');
window.parent.postMessage({message: {operation: operationId}}, '*');
}
After that I have a service in angular
var angular = require('angular');
var ListenerActionsServiceModule = angular.module('ui.apps.myApp.service',[
])
.service('listenerActionService', function($window, $rootScope){
this.$rootScope = $rootScope;
this.subscribeBeltEvent = function(){
$window.addEventListener('message', function(event){
if(event.origin === 'http://localhost:33333') {
propagateEvent(event);
}
else{
console.log('Origin not allowed');
}
}, false);
};
function propagateEvent(event) {
var eventName = 'eventName.';
var args;
if(event !== null && typeof event.data.message === 'object') {
eventName = eventName.concat('complexOperation');
args = event.data.message.operation;
}
else {
eventName = eventName.concat(event.data.message);
}
$rootScope.$broadcast(eventName, args);
}
});
module.exports = ListenerActionsServiceModule;
Everything is working fine except that, when I click the button inside the iframe the second or third time, the angular service is receiving twice or three times the event. It's like they are stacking in the window and after reading them they are not dissapearing. Is there any way to clean this after reading them? Or should I add to my event a field to know if I have read it or not?
Thank you
EDIT: This is happening only when we go back using the browser arrow
I'm not sure but your postMessage will never work unless you call your service.
In my case, I usually put an addEventListener in the main module and more specifically in the run method.
I am trying to capture a reload event from a controller. Inside my controller I have the following...
refresh = function() {
console.log("At least we know it ran!");
if ($window.performance) {
if ($window.performance.navigation.type === 1) {
console.log('page reloaded');
}
}
return null;
};
$window.onbeforeunload = refresh;
$scope.$on('$destroy', function(e) {
delete $window.onbeforeunload;
});
But the refresh function is never hit when I push the browser's reload button. What am I missing here?
I have an IdentificationView that has to call a method of another view in different app:
var NameAndIdentificationView = Application.Views.ItemView.extend({
loadMailingAddressView: function() {
//call to mailing address view method setAddress() from here
}
});
Now my MailingAddressView is something like this:
var MailingAddressView= Application.Views.ItemView.extend({
setAddress: function(address) {
if (address != null) {
// this.autoCompleteBox.data('inputData') = address;
ProWeb.EXTRACTED_ADDRESS = address;
this.model.set('mailingAddress', address);
}
}
});
I would like to know what is the way to call a method of one view from another. Please provide suggestions.
EDIT:
This is how my application has been setup:
First App is called.
Then the Controller is called.
From within the Controller, View is called and intialized.
So from within my NameIdentificationView, I'm calling the MailingAddress app that in turn controls all the process of calling the controller and it's view.
You can do it many ways using event channel,triggering and listening events on shared model, the simpler way of doing this is using Bsckbone events.
Trigger a event in caller
loadMailingAddressView: function () {
//call to mailing address view method setAddress() from here
Backbonw.trigger('setAddress')
})
and listen in callee's initalize
var MailingAddressView = Application.Views.ItemView.extend({
initialize: function() {
Backbone.on('setAddress', this.setAddress)
},
setAddress: function(address) {
if (address != null) {
// this.autoCompleteBox.data('inputData') = address;
ProWeb.EXTRACTED_ADDRESS = address;
this.model.set('mailingAddress', address);
}
},
});
make sure callee View is initialized by the time you trigger event
I am using this code from the SDK Tutorial Website:
var sidebar = require("sdk/ui/sidebar").Sidebar({
id: 'my-sidebar',
title: 'My Sidebar',
url: require("sdk/self").data.url("sidebar.html"),
onAttach: function (worker) {
// listen for a "ready" message from the script
worker.port.on("ready", function() {
// send an "init" message to the script
worker.port.emit("init", "message from main.js");
});
}
});
This works great. The problem is now that this only allows me to send something via the worker.port onAttach (and on 3 other events for the sidebar).
What I need is to use the emit function outside the scope of this sidebar. For example if I use in the same main.js an listener for a tab like
tabs.on('ready', function(tab) {
sidebar.worker.port.emit("init", "message from main.js");
}
This is not working. I also tried
sidebar.port.emit("init", "message from main.js");
or
worker.port.emit("init", "message from main.js");
Without success.
I have also tried to put the tab listener inside the onAttach of the sidebar (so a listener inside a listener) but that also is not working.
Does anybody have an idea on that one?
thanks.
Use the method described here:
var workers = [];
function detachWorker(worker, workerArray) {
var index = workerArray.indexOf(worker);
if(index != -1) {
workerArray.splice(index, 1);
}
}
var sidebar = require("sdk/ui/sidebar").Sidebar({
...
onAttach: function(worker) {
workers.push(worker);
worker.on('detach', function () {
detachWorker(this, workers);
});
}
});
Then to emit on open sidebars do:
workers.forEach(worker => {
worker.port.emit('some-message', data);
})
In which way I can do a global listener(or whatever) checking if we have internet connection visible in whole app no matter what controller I'm in and inside it using function showing simple angular material Alert in every app view.
So if I need to invoke this in any controller, I guess there's another way to do this, but I dont know how.
listener I wrote using addEventListener way.
You can subscribe to that event in the run section
.run(['$rootScope', '$window', function($rootScope, $window) {
$rootScope.online = $window.navigator.onLine;
if (!$rootScope.online) {
//do actions here
//for example go to special state, $state.go('offline')
alert('Offline!');
}
$window.addEventListener("offline", function() {
//do actions here
//for example set $rootScope.online = false;
alert('Offline!');
}, false);
$window.addEventListener("online", function() {
//do actions here,
//for example set $rootScope.online = true;
alert('Online!');
}, false);
}])
1) Since it's in the run block, it's quite on top of the hierarchy; executed when app is bootstrapped; I use this approach in several projects and and it works in all controllers;
2)The first if check is for first-time initial app start-up phase; because that may be that you are
using service workers and can app UI even when being offline;
user saved a shortcut on mobile with "Add to homescreen"
You could use something like Offline
Or roll your own
angular.module('plunker', [])
.factory('OnlineStatus', function($timeout) {
var isOnlineNow = true,
isOnline = function() {
$timeout(function() {
isOnlineNow = true;
});
},
isOffline = function() {
$timeout(function() {
isOnlineNow = false;
});
};
if (window.addEventListener) {
/*
Works well in Firefox and Opera with the
Work Offline option in the File menu.
Pulling the ethernet cable doesn't seem to trigger it.
Later Google Chrome and Safari seem to trigger it well
*/
window.addEventListener("online", isOnline, false);
window.addEventListener("offline", isOffline, false);
}
else {
/*
Works in IE with the Work Offline option in the
File menu and pulling the ethernet cable
*/
document.body.ononline = isOnline;
document.body.onoffline = isOffline;
}
return {
isOnline:function() {
return isOnlineNow;
}
};
})
.directive('online', ['OnlineStatus', function(OnlineStatus) {
return {
template:'<div class="online"></div>',
replace:true,
restrict:'E',
link:function(scope, elem, attrs) {
scope.$watch(function() {
return OnlineStatus.isOnline();
}, function(isOnline) {
elem.html(isOnline ? 'Online' : "Offline");
})
}
};
}])
See http://plnkr.co/edit/DrW8UdYsediusRMu1aMo?p=preview