Prevent MatDialog From Closing When Clicked Outside with pending changes - javascript

I want to prevent close on outside when there are pending changes.
I something like this, but with no result.
this.dialogRef.beforeClosed().subscribe(() => {
this.dialogRef.close(false);
//some code logic
//...
});
The disableClose on MatDialog have to stay false

Initially, while opening dialog, you can pass 'disableClose' as true, and later manually close dialog on backdrop click or escape click if there are no pending changes.
this.dialog.open(DialogComponent, { disableClose: true });
dialogRef.backdropClick().subscribe( () => {
if(!pendingChanges) dialogRef.close();
// else do nothing
});

Depending on the case, you can initially set disableClose as false, so that user can close it if there is no pending changes, depending on what that pending change is, if it is an async call for example, you can set the disableClose as true.
You can also then inject the MatDialogRef into the component itself and manually toggle disableClose per your requirements, so something like this:
constructor(private matDialogRef: MatDialogRef<WhateverYourDialogIsCalled>) {}
then in a async call it could be:
onSubmit() {
this.matDialogRef.disableClose = true;
this.myService.doSomething().subscribe(_ => {
this.matDialogRef.disableClose = false;
});
}

Related

React useState isn't setting opposite boolean correctly

I have a simple button on page with onClick event, and then useState hook that is by default set to false. Then I have elements on page, when I click on them I wanna do an action, but only if the state of that useState hook is set to true, which is done by if condition, but for some reason it passes it, even though the state should be false. My code:
Initiating the hook:
const [ isEraser, setIsEraser ] = useState(false);
Setting state on button click:
<span
className="scroll"
onClick={() => {
setIsEraser((isEraser) => !isEraser);
}}
>
The condition:
console.log('Eraser is set to', isEraser);
if (isEraser == true) {
// Code
}
The output of the console.log:
no changing state (is default false) -> false
changing state to true -> true
changing state back to false and triggering that event in which the condition is -> false, true, false
Edit:
I can't pass full component code, because it's kinda big, and some parts of code are protect by client contract, but the condition is in onClick event:
$body.on('click', '.tvs-annotated-text, .tvs-annotate-element', function(
e
) {
console.log('Eraser is set to', isEraser);
if (isEraser === true) {
setIsAlert(1);
// Odstraníme vybranému elementu backround
this.style.backgroundColor = '';
this.classList.remove('tvs-annotated-text');
this.classList.remove('tvs-annotate-element');
}
});
pretty sure you just need to do setIsEraser(!isEraser)
You don't have to use a function to set state setIsEraser((isEraser) => !isEraser); → setIsEraser(!isEraser)
Allright, so the problem was that the onClick trigger was written in jQuery, after rewriting it to normal javascript it works now. Big thanks to you guys.
In the setIsEraser you need to pass the last state. you passed the initial state in it so every time you press the button it passes false as isEraser.
change the isEraser in setIsEraser function to something else like pre or previous, etc.
<span
className="scroll"
onClick={() => {
setIsEraser((pre) => !pre);
}}
>
In this way pre would be the last state not the initial state and your program will work just fine.

Vue JS Event bus data not working outside scope of event

I am using event bus to show alert on update data.so whenever user update the data i want to show an alert showing "Data is udpated" so for that i am using event bus
here is BlogEdit.vue Component where i am firing event
app.$router.push('/', () => {
vueBus.$emit('showAlertBox')
})
And In BlogList.vue I am listning for this event
data: function(){
return {
showalert: false,
}
},
vueBus.$on('showAlertBox',(data) => {
this.showalert = true;
console.log(this.showalert); //Returns True
})
console.log(this.showalert); //Returns False
But the result is unexpected as it change back to false.
Why this.showalert changed to false ? So that cause to not showing alert box.
Since i am new to vue js i read the documenatation and other solutions but i cant figure out where am i going wrong with this.

How to open/close sidebar in TinyMCE

In the official TinyMCE docs is nothing written about the possibility to manually open/close the sidebar:
https://www.tinymce.com/docs/advanced/creating-a-sidebar/#editorsidebarapi
Can anybody help me? I think it must be something like this:
editor.getSidebar('mysidebar').close();
I need it, because I want to close my custom sidebar in my file browser callback.
Use tinymce.activeEditor.execCommand('togglesidebar', false, 'sidebarname'); to toggle the sidebar. You could place event dispacthers and listeners to know if it is currently opened or closed:
tinymce.PluginManager.add('cheminfo', function (editor, url) {
editor.ui.registry.addSidebar('cheminfo', {
tooltip: 'My sidebar',
icon: 'comment',
onShow: function (api) {
var event = new CustomEvent('tinymce-chem-sidebar', {'detail': true});
window.parent.document.dispatchEvent(event);
},
onHide: function (api) {
var event = new CustomEvent('tinymce-chem-sidebar', {'detail': false});
window.parent.document.dispatchEvent(event);
}
});
});
Then (I am using React):
// detect sidebar state open/close
document.addEventListener('tinymce-chem-sidebar', function (e) {
setOpen(e.detail);
});
PS: Make sure the sidebar's name is lowercase or it won't work
adding to #Kristiyan Tsvetanov's solution, an alternative to using event listeners in determining open/close state of sidebar, the following code can be used:
function is_sidebar_open() {
//class names taken from using inspect on the
//sidebar area of the editor in a browser session
if ($(".tox-sidebar__slider").hasClass("tox-sidebar--sliding-closed")) {
return false;
}
else {
return true;
}
}
function open_sidebar(){
if (is_sidebar_open() == false){
tinymce.activeEditor.execCommand('togglesidebar', false, 'sidebarname');
}
}
function close_sidebar(){
if (is_sidebar_open() == true){
tinymce.activeEditor.execCommand('togglesidebar', false, 'sidebarname');
}
}

protractor test before initial promises resolve

I want to test the state of the controller after initialization completes, but before promises resolve.
I have a button which is disabled (by class) until loading completes:
<button ng-class="{disabled: isLoading}">Show</button>
When the controller is initialized, an ajax call is made and when it resolves, the isLoading is set to false:
$scope.isLoading = true;
$http.get('/list')
.then(function(response) {
$scope.list = response.data;
$scope.isLoading = false;
});
When I test the button using protractor, there is no disabled class.
it('should enable the button after load completes', function() {
element(by.buttonText('Show')).getAttribute('class')
.then(function(buttonClasses) {
expect(buttonClasses).toContain('disabled');
});
});
I modified the button to have another class, just to see I'm not going bonkers:
<button ng-class="{disabled: isLoading, enabled: !isLoading}">Show</button>
and the test:
it('should show the select tables list after clicking the Change button', function() {
element(by.buttonText('Show')).getAttribute('class')
.then(function(buttonClasses) {
expect(buttonClasses).toContain('enabled');
});
});
Now the test passes.
I'm guessing that waitForAngular is part of the controller initialization process. How do I test the state of the button Before the promise resolves?
You can set browser.ignoreSynchronization = true before finding the element/class to not wait for promises in the app to resolve
it('should show the select tables list after clicking the Change button', function() {
browser.ignoreSynchronization = true;
expect(element(by.buttonText('Show')).getAttribute('class')).toContain('disabled');
browser.ignoreSynchronization = false;
});
Note you rarely need to use .then callbacks for expect, since expect handles unwraping of the promises.

Asynchronous call confirmation dialog in event

I want to return a boolean value from a jQuery confirmation dialog and return that value to an event (to either continue or stop default execution of an event). I know about asynchronous calls but I really can't get around this. This is what I have until now:
function moveConfirmation() {
var defer = $.Deferred();
$('#dialog-move-confirm').dialog({
resizable: false,
width: 400,
height: 200,
autoOpen: true,
modal: true,
buttons: {
'Move Separately': function() {
$(this).dialog('close');
defer.resolve(true);
},
'Move Together': function() {
$(this).dialog('close');
defer.resolve(false);
},
Cancel: function() {
$(this).dialog('close');
defer.resolve(false);
}
}
});
return defer.promise();
}
scheduler.attachEvent('onBeforeEventChanged', function(id, ev) {
// if move contemporaneous exams, alert user to choose if move together or separately
var state = scheduler.getState();
var saveEvent = false;
if (state.drag_mode === 'move') {
moveConfirmation().then(function(move) {
saveEvent = move;
});
}
return saveEvent;
}
What is happening is that saveEvent is still false and returning before the promise. What should I do? I also tried another promise.. but it still comes back to the same thing. Anyone sees a workaround for this?
You must know that the return statement within onBeforeEventChanged will always return false, since moveConfirmation().then(...) is async.
You will probably have to always cancel the onBeforeEventChanged event like you are doing, but rather than simply setting saveEvent = move; within the moveConfirmation handler, you will have to re-trigger the attempted operation programmatically in case the user wanted to proceed (perhaps using updateEvent).
Please also note that you need a mechanism in place to avoid having the re-triggering process to invoke your dialog box again (e.g. if onBeforeEventChanged is fired when calling updateEvent).
EDIT: Note that you can also do the opposite if it looks better on the UI, always accept event changes, but undo them if needed as per the moveConfirmation's response.

Categories