Prevent 'Leave site?' dialog for Google Forms inside iframe? - vue.js

My Vue component uses Google Forms inside an iframe. The problem is, that when user tries to navigate to another page, she will get 'Leave site? Changes that you made may not be saved.' dialog. How can I disable this in my component?
EDIT: I noticed that this caused by the fact, that one field is prefilled on the google forms. Is there a way to bypass the dialog, if there a prefilled fields?

I am spitballing here but I believe that the internal page inside the iframe sets an event handler for the window.beforeunload event, if your page does not use this event, you could
window.onbeforeunload = function () {
return undefined;
};

I found one solution. Add v-if the the iframe:
<iframe v-if=!hideGoogleForm" ...>
Then to mounted():
window.onbeforeunload = () => {
this.hideGoogleForm = true;
};
The dialog is still shortly shown but then automatically closed when the component is destroyed.

Related

Scrolling to v-expansion-panel opening

I'm trying to build a mobile small application using v-expansion-panels to display a list.
The idea is that when the user adds a new item in such list it will open the new panel and scroll down to such new panel.
I found a goTo() method in the $vuetify variable, unfortunatly the v-expansion-panels transition (the "opening") take some time and the goTo() won't completely scroll down because of the scrollbar height changes.
So from my understanding I need to detect the end of the transition (enter/afterEnter hook).
Per the vuetifyjs documentation, I could hope to have a "transition" property on my component. (Which isn't the case anyway). But such property is only a string so I can't hook into it.
My other idea is to, somehow, find the transition component and hook into it. Unfortunatly I have trouble understanding el/vnode and the way vuejs is building is tree like the vue-devtool show and I can't get the transition component. When debugging (in the enter hook callback of the transition) it is like the component/el/vnode has a parent but isn't the child of anybody.
Is there a way to do what I'm looking for?
Here is a jsfiddler of what I currently do: https://jsfiddle.net/kdgn80sb/
Basically it is the method I'm defining in the Vue:
methods: {
newAlarm: function() {
const newAlarmPanelIndex = this.alarms.length - 1;
this.alarms.push({title: "New line"});
this.activePanelIndex = newAlarmPanelIndex;
// TODO:
this.$vuetify.goTo(this.$refs.alarmPanels[newAlarmPanelIndex]);
}
}
Firstly you should open manually panel and then use goTo with a timeout.
It works for me, just give some time to a panel to open.
<v-expansion-panels v-model="alarmPanels">
<v-expansion-panel>
<div id="example" />
</v-expansion-panel>
</v-expansion-panels>
this.alarmPanels.push(0); // Use index of expansion-panel
setTimeout(() => {
this.$vuetify.goTo(`#${resultId}`);
}, 500);

Durandal Modals and navigation (i.e. back button)

This issue is easily seen in the durandal sample application:
1) Navigate to "Modal Dialogs" demo
2) Click the button to show the modal
3) Click the browser back button
When doing this, the page navigates to the previous screen while keeping the dialog open, which is almost never what you want.
Is there a best practice here for either closing dialogs or preventing navigation if one is open?
You can tie into the canDeactivate callback. Check if the modal is open and either prevent it or if they want to leave, close it
While I don't expect this answer to be immediately applicable to many out there, I wanted to throw it out there in case it helps someone.
We use typescript to create our viewmodels, and we have a base viewmodel to encapsulate common functionality (as well as expose the dataservice, pub/sub, etc). In this viewmodel this approach seems to work well:
public ShowDialog(viewModel: any) {
// create a subscription to the router so that we can forcibly close the dialog in the event of a routing call
var subscription = router.on('router:route:activating');
subscription.then(() => {
// we will hit this block if the router is activating while this dialog is open
var moduleId = viewModel.__moduleId__ || '[No Id]';
system.log('Navigation detected while dialog is open - the dialog will now be forcibly closed. (' + moduleId + ')', viewModel);
dialog.close(viewModel);
});
var promise = App.showDialog(viewModel);
promise.then(() => {
subscription.off(); // kill the router subscription since the dialog is closed at this point
});
return promise;
}
Consumers can use this function as a direct substitution to durandals' dialog to opt-in to the auto-close functionality.

WinJS NavBar event handler crashing Windows 8.1 HTML5/JS app when navigating to another page

I am developing an HTML/JS app for Windows 8.1 and am having trouble debugging a crash that is ocurring on within a handler attached to the top NavBar object when the user navigates from the page the handler is attached to.
The functionality is pretty simple: when the user lands on the screen in question, I am automatically displaying a WinJS Flyout using it's .show() method. Now, when the user invokes the top NavBar object, I have a handler that hides the Flyout object. I also have another handler that .shows() the Flyout when the NavBar is dismissed.
The problem occurs when the user navigates to another page. Here is my code for the screen in question:
var appBar = class.that.constructs.NavBar;
ready : function (element, options) {
var self = this;
...
appBar.topControl.onbeforeshow = self.hideFlyout;
appBar.topControl.onbeforehide = self.showFlyout;
$('#flyout').addClass('activated');
$('#flyout')[0].winControl._sticky = true;
$('#flyout')[0].winControl.show();
},
hideFlyout: function() {
$('#flyout').topControl.winControl.hide();
},
showFlyout: function() {
$('#flyout').topControl.winControl.show();
},
unload: function () {
appBar.topControl.onbeforeshow = null;
appBar.topControl.onaftershow = null;
}
As you can see, I am removing the event handlers upon unloading the page, but that doesn't seem to do the trick. I still get this crash error:
JavaScript runtime error: Unable to get property 'classList' of undefined or null reference
It crashes on the showFlyout handler. Does anybody have any suggestions as to how to avoid the crash upon navigating to a new page?
The show methos of the flyout wants an element as a mandatory parameter, it is the element it will be attacched to.
in your case you have to find an element and pass it to your function, for example:
var myButton= document.getElementById("myButton");
$('#flyout').topControl.winControl.show(myButton);
Check this page for a more extensive example: http://msdn.microsoft.com/en-us/library/windows/apps/br211726.aspx

prevent anchor tag from navigating to home page

I have a regular anchor tag with href attribute set to "#". Normally, this prevents from any navigation but in durandal it navigates me to the home view. How can I stop it from navigating to that view?
I can't change the html and stylings. It needs to be that anchor tag. But I can bind a click event to it. Is there any way to cancel navigation in anchor click event?
regards
Bind a click event to it and call event.preventDefault()
Example
$(function() {
$('#someAnchor').click(function(event) { event.preventDefault(); });
});
This will prevent the browser from propagating the click event and nothing will happen. But inside the click event you can do whatever logic you want.
If you are using knockout to bind the click event then please refer to this stackoverflow post on how to do it from a knockout binding.
EDIT ** Per Tyrsius' comments its a better practice to use the knockout binding to bind a click event.
So, instead it is recommended you do:
ClickMe
clickhandler = function (e) {
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
};
Have all your anchor links start with a prefix. Then have in your router.guardRoute function this:
if (_.startsWith(instruction.fragment, YOUR_PREFIX))
return false;
}
Worked well for me and no need to add anything else to your app views.
PS. _.startsWith is lodash function. If not using lodash do JS string indexOf or whatever

Dojo Form onSubmit Event

I would like to use a dijit.form.Form for my application login, allow dojo to perform the form validation and use xhrPost to submit the form. I believe this can readily be done by over-riding the onSubmit event and using this.validate() to validate the login form.
For successful login, how can I tell when the onSubmit event is done so I can safely remove the login form from the DOM?
From the documentation it appears that dojo (validate?) may continue to reference the login form in the DOM after returning (false in my case) from onSubmit. Is there a way to "listen" for the onSubmit event to complete so I can safely remove the login form from the DOM?
EDIT
#BuffaloBuffalo - I tried your example and called dojo.xhrPost within the onSubmit this.validate().
The onSucessFunction received control and completed processing prior to returning to the statement after dojo.xhrPost which is the return false from the onSubmit event. To recap, this.validate() was true, the login form was validated by dojo and the onSuccessFunction received control as shown in your example. However, rather than hide the login DOM, I actually remove it completely with dojo 1.7.3 AMD syntax below:
var loginDOMnode = dom.byId("Login");
array.forEach(registry.findWidgets(loginDOMnode), 'item.destroyRecursive(true)');
domConstruct.empty(loginDOMnode);
I am using IE 9 and I get the following error:
SCRIPT5007: Unable to get value of the property 'value': object is
null or undefined ValidationTextBox.js, line 14 character 1
Since I return false from onSubmit this.validate() after I remove the login form from the DOM, it appears that I am removing it from the DOM before dojo is done with the ValidationTextBox. Is there a way to have the onSucessFunction run after I return false from onSubmit this.validate()?
If you are using ajax (e.g. xhrPost) to submit the login process, you need to listen to the return of that asynchronous event. In your custom Form:
onSubmit:function(e){
//stop event
dojo.stopEvent(e);
//validate your form
var onSucessFunction = function(){
//hide login dom
};
var onErrorFunction = function(){
//show an error
};
dojo.xhrPost({
//parameters
}).then(onSucessFunction,onErrorFunction);
},