I'm writing my first electron app, so please be lenient :)
When the user presses a button on the main Window, there should open a new window which shows some json string.
This event gets cought by ipcMain:
ipcMain.on("JSON:ShowPage", function(e, item) {
createJSONWindow(item);
})
This is the function where I create the new window:
function createJSONWindow(item) {
let jsonWin = new BrowserWindow({
width: 600,
height: 800,
center: true,
resizable: true,
webPreferences:{
nodeIntegration: true,
show: false
}
});
jsonWin.loadFile("jsonView.html");
ipcMain.on('JSON_PAGE:Ready', function(event, arg) {
jsonWin.webContents.send('JSON:Display', item);
})
jsonWin.once('ready-to-show',()=>{
jsonWin.show()
});
jsonWin.on('closed',()=>{
jsonWin = null;
});
}
Now to my question, when I have multiple JSONWindows open, every single one of them gets the JSON:Display Message and updates it's content. Shouldn't they work independently from each other? The jsonWin is always a new BrowserWindow, isn't it?
Thanks in advance.
The problem is this code:
ipcMain.on('JSON_PAGE:Ready', function(event, arg) {
jsonWin.webContents.send('JSON:Display', item);
})
Every time you create a new window, you are having ipcMain subscribe to the same message. This means that when ipcMain gets the 'JSON_PAGE:Ready' message, it calls every single callback it has registered and sends a message to every single window.
The simplest solution in this case is to use the event that's passed to the ipcMain handler to send the message to the renderer that sent it to main. Second, subscribe a single time outside of createJSONWindow:
ipcMain.on('JSON_PAGE:Ready', function(event, arg) {
e.sender.send('JSON:Display', item);
});
function createJSONWindow() { ... }
However, is 'JSON:Display' simply sent when the page has loaded? If so, you can subscribe the window's webContents to the did-finish-load event which fires when the page has loaded.
jsonWin.webContents.on("did-finish-load", () => {
jsonWin.webContents.send(...);
});
Related
I am trying to show Angular Material Dialog Box (Popup window), when User hits the Chrome Window Close button (upper right). The Dialog modal should hold prompt the user, if they want to save changes, or cancel,
However it only shows the modal for quick second, then closes without waiting for user.
Using code reference below. How can it be fixed ?
How can we detect when user closes browser?
#HostListener('window:beforeunload', ['$event'])
beforeunloadHandler(event) {
this.openDocumentSaveDialog();
}
public openDocumentSaveDialog(): void {
const documentSaveDialogRef = this.documentSaveDialog.open(DocumentSaveDialogComponent, {
width: '600px',
height: '200px',
disableClose: true,
autoFocus: false,
data: null
});
documentSaveDialogRef.afterClosed().subscribe(result => {
this.closeMenu.emit()
});
}
Note: We do Not want to display Native chrome browser popup, but a custom popup .
Angular Material Dialog Box:
https://material.angular.io/components/dialog
The beforeunload event doesn't support a callback function that returns a promise so you can't show the popup and return value as it isn't a sync operation.
what you can do instead is just returning false always or call
event.preventDefault()
and if the user decided to leave the page you can call
window.close(....)
if not you already have cancelled the event.
so your code should look something like this
#HostListener('window:beforeunload', ['$event'])
beforeunloadHandler(event) {
this.openDocumentSaveDialog();
event.preventDefault();
event.returnValue = '';
return false;
}
public openDocumentSaveDialog(): void {
const documentSaveDialogRef =
this.documentSaveDialog.open(DocumentSaveDialogComponent, {
width: '600px',
height: '200px',
disableClose: true,
autoFocus: false,
data: null
});
documentSaveDialogRef.afterClosed().subscribe(result => {
if(!result)
window.close()
this.closeMenu.emit()
});
}
I am afraid that browser security won't allow you to prevent the user from closing the window. In my opinion this is not possible, you can only show the native window that warns the user about losing the data if closing the browser window.
This works for me. But you have no control over the display!
#HostListener('window:beforeunload', ['$event'])
showAlertMessageWhenClosingTab($event) {
$event.returnValue = 'Your data will be lost!';
}
I have a button's onclick set to use the following function EditContact. This function sets up a jquery dialog, gets the data from the server and displays it. Everything works but I would like to get it to work a little better. Right now the empty dialog pops up for the time it takes the code to go and fetch the content from the server then the dialog populates with the content. My question is how can I get the dialog to not pop up until the content has been received.
function EditContact() {
$('#editContactView').dialog({
modal: true,
width: 'auto',
position: ['top', 'center'],
resizable: false,
autoOpen: false,
open: function (event) {
var szAction = "Content url for this example";
$(this).load(szAction,
function (response, status, xhr) {
$('#editContactView').dialog('open');
return false;
});
}
});
$('#editContactView').dialog('open');
}
I think you should be able to essentially turn what you have inside out and and open the dialog on $().load() completion. Something like this might do it:
function editContact() {
var szAction = "Content url for this example";
$(this).load(szAction, function (response, status, xhr) {
$('#editContactView').dialog({
modal: true,
width: 'auto',
position: ['top', 'center'],
resizable: false
});
});
}
Edit:
Notice I removed the {autoOpen: false}. This will create it and open it in one shot after you receive the content.
You are calling .dialog('open') twice: in the end of the code and in the callback for the loading.
As JavaScript is asynchronous, it runs the line $('#editContactView').dialog('open'); in the end before the data is received.
Removing this line should solve the problem.
I am learning JavaScript and I got stuck creating a function to minimize a window. The problem is that this functions seems to stack in itself so many times.
Gere is my principal function :
function displayChatWindow(user, status, avatar, id){
var template = _.template($("#windowTemplate").html(), {userName: user, userStatus: status, userAvatar: avatar, userId: id});
stackingWidth = stackingWidth - boxWidth;
console.log(stackingWidth);
$("body").prepend(template);
$(".messages-container").slimScroll({
height: '200',
size: '10px',
position: 'right',
color: '#535a61',
alwaysVisible: false,
distance: '0',
railVisible: true,
railColor: '#222',
railOpacity: 0.3,
wheelStep: 10,
disableFadeOut: false,
start: "bottom"
});
$("#" + id).css({
top: absoluteY,
left: stackingWidth
});
$(".minimize-others").on("click", displayOthersChat);
$(".chat input, .chat textarea").on("focus", cleanInputs);
$(".chat input, .chat textarea").on("blur", setInputs);
}
This function receives some parameters and with a template creates the chat window. At the end it applies the function to minimize the window (displayOthersChat) and load plugins and stuff for each window.
My displayOtherChats function:
function displayOthersChat(e){
/*e.preventDefault();*/
var This = $(this).parent().parent();
var minimize = This;
if(!This.hasClass("draggable")){
This.animate({
top: windowHeight - boxHeight - 20
});
This.addClass("draggable");
This.draggable({handle: ".header"});
var timeOut = setTimeout(function() {
This.find(".minimize").toggleClass("rotate");
}, 500);
}else{
This.draggable("destroy");
This.removeClass("draggable");
var timeOut = setTimeout(function() {
This.find(".minimize").toggleClass("rotate");
}, 500);
This.animate({
top: absoluteY
});
}
/*return false;*/
}
This seems to work really well. If I open my first window it displays and also minimizing the window works. When I open another window, the last window works correctly but the first window opens when I try to minimize it.
It seems that it calls the function twice, and if I open a third window, the first window calls the function three times.
I actually don't know whats going on, I will appreciate if you guys could help me. I also leave a link so you guys can see whats going on: http://s3.enigmind.com/jgonzalez/nodeChat.
The problem seems to be that you are binding the same event handler to the same elements over and over again.
$(".minimize-others").on("click", displayOthersChat); will bind displayOthersChat to all existing elements with class minimize-others. .on always adds event handlers, it does not replace them. So if you call displayChatWindow multiple times, you are binding the event handler to the .minimize-others elements multiple times.
You only want to bind the handler to the window that was just created, for example:
// create reusable jQuery object from HTML string.
var $template = $(template).prependTo('body');
// instead of $("body").prepend(template);
// ...
$template.find('.minimize-others').on('click', displayOthersChat);
Same goes for the other event handlers.
Alternatively, you could bind the event handler once, outside of the function and use event delegation to capture the event:
$(document.body).on('click', '.minimize-others', displayOthersChat);
I have a jQuery dialog that appears and loads an external page. In that page i am running a setInterval() function that queries my server continuously every 1 second (AJAX). The problem is that when i close the dialog, the setInterval doesn't stop running.
here is the code for the dialog:
var theUrl = 'someUrl';
var popUp = document.createElement('div');
$(popUp).dialog({
width: 400,
height: 270,
title: "Some Title",
autoOpen: true,
resizable:false,
close: function(ev, ui) {
$(this).dialog('destroy');
},
modal: true,
open: function() {
$(this).load(theUrl);
}
});
I tried calling $(this).dialog('destroy') and $(this).remove() and document.body.removeChild(popUp) on close. nothing worked. is there anyway to 'unload' the loaded page?
setInterval returns a handler that you can pass to clearInterval to stop the function from running. Here's a basic example of how it works.
var handler = setInterval(function() {}, 2000);
clearInterval(handler);
For your example you'd want to call clearInterval in the close method of the ui.dialog.
Docs:
setInterval - https://developer.mozilla.org/en/window.setInterval
clearInterval - https://developer.mozilla.org/en/DOM/window.clearInterval
Edit
You will not be able to call clearInterval without the stored handler from setInterval, therefore if the call to setInterval is in another script the only way you're going to capture the handler is to override window.setInterval itself.
$(function() {
var originalSetInterval = window.setInterval;
var handlers = [];
window.setInterval = function() {
handlers.push(arguments[0]);
originalSetInterval(arguments);
};
$('whatever').dialog({
close: function() {
for (var i = 0; i < handlers.length; i++) {
clearInterval(handlers[i]);
}
handlers = [];
}
});
});
Note that the code to override window.setInterval must come before including the <script> tag to bring in the external file. Also this approach will clear all interval functions whenever clearInterval is called, therefore this is not ideal, but it's the only way you're going to accomplish this.
There are menu button ("clients"), tree panel with clients list (sorted by name) and viewer with selected client details. There is also selectionchange action..
My task - on button click switch to client view and select and load details for first client every time button has been clicked. My problem - store is not loaded, how waiting until ext js will autoload data to the store?
my controller code:
me.control({
'#nav-client': {
click: me.onNavClientClick
},
...
'clientlist': {
// load: me.selectClient,
selectionchange: me.showClient
}
});
onNavClientClick: function(view, records) {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...
Two main questions:
is it good solution in my case? (to select first client in tree panel)
var first = me.getClientsStore().first();
// i use another store to get first record because of i dont know how to get first record (on root level) in TreeStore
...
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
i know this code works ok in case of "load: me.selectClient," (but only once),
if i place this code on button click - i see error
Uncaught TypeError: Cannot read property 'id' of undefined
because of me.getClientsListStore() is not loaded.. so how to check loading status of this store and wait some until this store will be completely autoloaded?..
Thank you!
You can listen the store 'load' event. Like this:
...
onNavClientClick: function(view, records) {
var me = this;
// if the store isn't loaded, call load method and defer the 'client view' creation
if (me.getClientsStore.getCount() <= 0) {
me.getClientsStore.on('load', me.onClientsStoreLoad, me, { single : true});
me.getClientsStore.load();
}
else {
me.onClientsStoreLoad();
}
},
onClientsStoreLoad : function () {
var me = this,
content = Ext.getCmp("app-content");
content.removeAll();
content.insert(0, [{xtype: 'clientcomplex'}]);
var first = me.getClientsStore().first();
if (first) {
Ext.getCmp("clientList").getSelectionModel().select(me.getClientsListStore().getNodeById(first.get('clientId')));
}
},
...