Simply speaking, I have a form, and a field.
<!-- inner.html -->
<form id="inner_form">
<input type="text" name="username" />
<input type="submit" />
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function() {
$('#inner_form').submit(function() {
alert('Inner submit is triggered!');
});
});
</script>
The above code goes well: when I click the submit button, it triggers the submit event of #inner_form, and alerts the sentence: Inner submit is triggered!
My problem is, when I make another page, and loads the inner.html inside an <iframe>:
<!-- outer.html -->
<iframe id="the_frame" src="inner.html">
</iframe>
<button id="outer_submit">Submit Inner</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(function() {
$('#outer_submit').click(function() {
// it don't trigger the inner submit() event!
$('#the_frame').contents().find('#inner_form').submit();
});
});
</script>
As the above code (which might not working well in the snnipet), I click the #outer_submit button, and the #inner_form do submitted, but the event I defined inside it don't triggered!
Why do this happen? And if I want the inner event triggered well with outer action, how can I got it?
While I can't give you an answer as to 'why', here's some discoveries I made while testing this:
Replacing the .submit() action with
$('#the_frame').contents().find('#inner_form input[type="submit"]').click();
Will trigger the alert. This isn't a proper fix though, because there's more ways to submit a form. Still, it shows that the events are not completely broken. So I dug deeper.
I tried using native javascript events instead of jquery's .submit([function]) bind in inner.html:
<form id="inner_form" onsubmit="alert('hi')">
That actually shows the alert. And so does this:
$('#inner_form')[0].onsubmit = function() {
alert('Inner submit is triggered!');
}
So there seems to be something wrong with the way jQuery sets and/or detects its own submit() method.
One more try:
$('#inner_form').on('submit', function() {
alert('Inner submit is triggered!');
});
This also shows the submit!
My wild guess is that for some reason when the events in inner.html are being bound, it doesn't know the form yet, even though the bind is wrapped in an implicit document.ready event through $(function(){ .. });.
As for the how and why of this I remain in the dark, but the fix is simple: wrap your event binds in an .on() method.
Related
I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.
I have a form in Angular that has two buttons tags in it. One button submits the form on ng-click. The other button is purely for navigation using ng-click. However, when this second button is clicked, AngularJS is causing a page refresh which triggers a 404. I’ve dropped a breakpoint in the function and it is triggering my function. If I do any of the following, it stops:
If I remove the ng-click, the button doesn’t cause a page refresh.
If I comment out the code in the function, it doesn’t cause a page refresh.
If I change the button tag to an anchor tag (<a>) with href="", then it doesn’t cause a refresh.
The latter seems like the simplest workaround, but why is AngularJS even running any code after my function that causes the page to reload? Seems like a bug.
Here is the form:
<form class="form-horizontal" name="myProfile" ng-switch-when="profile">
<fieldset>
<div class="control-group">
<label class="control-label" for="passwordButton">Password</label>
<div class="controls">
<button id="passwordButton" class="secondaryButton" ng-click="showChangePassword()">Change</button>
</div>
</div>
<div class="buttonBar">
<button id="saveProfileButton" class="primaryButton" ng-click="saveUser()">Save</button>
</div>
</fieldset>
</form>
Here is the controller method:
$scope.showChangePassword = function() {
$scope.selectedLink = "changePassword";
};
If you have a look at the W3C specification, it would seem like the obvious thing to try is to mark your button elements with type='button' when you don't want them to submit.
The thing to note in particular is where it says
A button element with no type attribute specified represents the same thing as a button element with its type attribute set to "submit"
You can try to prevent default handler:
html:
<button ng-click="saveUser($event)">
js:
$scope.saveUser = function (event) {
event.preventDefault();
// your code
}
You should declare the attribute ng-submit={expression} in your <form> tag.
From the ngSubmit docs
http://docs.angularjs.org/api/ng.directive:ngSubmit
Enables binding angular expressions to onsubmit events.
Additionally it prevents the default action (which for form means sending the request to the server and reloading the current page).
I use directive to prevent default behaviour:
module.directive('preventDefault', function() {
return function(scope, element, attrs) {
angular.element(element).bind('click', function(event) {
event.preventDefault();
event.stopPropagation();
});
}
});
And then, in html:
<button class="secondaryButton" prevent-default>Secondary action</button>
This directive can also be used with <a> and all other tags
You can keep <button type="submit">, but must remove the attribute action="" of <form>.
I wonder why nobody proposed the possibly simplest solution:
don't use a <form>
A <whatever ng-form> does IMHO a better job and without an HTML form, there's nothing to be submitted by the browser itself. Which is exactly the right behavior when using angular.
Add action to your form.
<form action="#">
This answer may not be directly related to the question. It's just for the case when you submit the form using scripts.
According to ng-submit code
var handleFormSubmission = function(event) {
scope.$apply(function() {
controller.$commitViewValue();
controller.$setSubmitted();
});
event.preventDefault();
};
formElement[0].addEventListener('submit', handleFormSubmission);
It adds submit event listener on the form.
But submit event handler wouldn't be called when submit is initiated by calling form.submit(). In this case, ng-submit will not prevent the default action, you have to call preventDefault yourself in ng-submit handler;
To provide a reasonably definitive answer, the HTML Form Submission Algorithm item 5 states that a form only dispatches a submit event if it was not submitted by calling the submit method (which means it only dispatches a submit event if submitted by a button or other implicit method, e.g. pressing enter while focus is on an input type text element).
See Form submitted using submit() from a link cannot be caught by onsubmit handler
I also had the same problem, but gladelly I fixed this by changing the type like from type="submit" to type="button" and it worked.
First Button submits the form and second does not
<body>
<form ng-app="myApp" ng-controller="myCtrl" ng-submit="Sub()">
<div>
S:<input type="text" ng-model="v"><br>
<br>
<button>Submit</button>
//Dont Submit
<button type='button' ng-click="Dont()">Dont Submit</button>
</div>
</form>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.Sub=function()
{
alert('Inside Submit');
}
$scope.Dont=function()
{
$scope.v=0;
}
});
</script>
</body>
Just add the FormsModule in the imports array of app.module.ts file,
and add import { FormsModule } from '#angular/forms'; at the top of this file...this will work.
I used correct google tagging to enable cross-domain tracking. When the form is submitted by clicking on submit button the ?ga=... will be added to the destination URL but, it won't be added if I trigger the submit event by JS.
Code is as follows:
<head>
<script>
//All other common JS code exist
gtag('set', 'linker', {
'domains': ['example.com'],
'decorate_forms': true
});
gtag('config', 'UA-...');
</script>
</head>
<body>
<form method="POST" action="https://example.com/a/b">
<button type="submit">Submit</button>
</form>
<button id="bt">Click to submit form using JS</button>
<script>
$(document).on('click', '#bt', function(e){
$('form').submit();
});
</script>
</body>
If I add submit button to form and click on it directly the destination will be something like https://example.com/a/b?_ga=.... However, when I submit the form via JS, destination URL is just like the form action without GA appendix.
I have to note that I'm using gtag and not GTM.
It can be solved in two different ways:
Method 1
We can change the submit trigger to a click trigger on the submit button. Don't know why but, it solves the issue :)
$(document).on('click', '#bt', function(e){
$('form button[type="submit"]').trigger('click');
});
Method 2
We can handle anything we want in the submit event instead of the click event on some other button other than submit.
$(document).on('submit', 'form', function(e){
//Do your stuff and handle the event
return true;
});
Although the problem seems to be solved, the main question still exists and it seems it is pointing to a potential bug for gtag or jquery form.submit(). Therefore, if you can provide any solution or answer for the open question, go ahead and publish your post and I'll make your answer as a correct one.
Hello everyone and sorry for my english.
Following this jdfiddle, I have a problem I don't understand.
First I change the value of the input, then I click on the button and what I expected to see is "click" but I see "change" meaning onclick is called after onchange.
<input type="text" onChange="alert('change')" />
<button type="button" onClick="alert('click');">Click!</button>
I found on this post that it's because of chrome which fires onchange event before the onclick event. But I don't really have the same need as this post because my event are not declared in the same tag. And secondly, if I click on the button I would like to only execute the onclick function and not onclick and then onchange (this methods consists in using onMouseDown).
Do you have a good method to do that?
Ok so I can see that you really wan't this.
You could let the on change function run first, and then afterward see what has focus, if it is that button, you would know that it was clicked, and thus was the reason for loosing focus.
you cannot check this while the change function is running, as the body still has focus at this time..
<head>
<script language="javascript">
function focussed()
{
var triggerElement = document.activeElement
alert(triggerElement)
console.info(triggerElement)
}
function change()
{
alert("change")
setTimeout(focussed, 1)
return true
}
</script>
</head>
<body>
<input type="text" onChange="alert('change')" />
<button type="button" onClick="alert('click');">Click!</button>
</body>
Im writing a class that replaces all input type="button" and input type="submit" in the document with a custom button, that is actually a span stuffed inside of an anchor tag, i've got everything written, and it all works, except the inline onsubmit event is not being fired when the form is submitted with a javascript.
Actually, even writing a static anchor tag
Submit
will not fire the inline onsubmit event for the form, but <input type="submit" /> will fire the event...anyways there has to be a way to fire this onsubmit event with javascript.
Heres a snippet of what im working with:
click: function() {
//get parent form
var thisForm = this.getParent('form');
//fire onsubmit event
thisForm.fireEvent('submit'); //this doesnt work!
//submit form...the event isn't fired here either!
thisForm.submit();
}
anybody have any ideas? this class needs to need no configuration and there are some older sites using our cms system that we want to plug this into, and there are quite a few inline submit events on the forms we need to account for
Thanks
UPDATE,
I took the suggestion and came up with this:
if(this.getParent().onsubmit()) {
this.getParent().submit();
}
works perfectly for evaluating the forms onsubmit event and submitting the form based on its output, but what if the function doesn't exist at all? Any ideas?
Firing submit on a form doesn't trigger it's inline onSubmit, this is default javascript behaviour (found this: http://www.codestore.net/store.nsf/unid/DOMM-4QS3RL/)
You can try calling onsubmit yourself though, this works for me:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/mootools/1.3.1/mootools-yui-compressed.js"></script>
<script type="text/javascript" charset="utf-8">
window.addEvent('domready', function(e) {
$$('span.submit').each(function(el) {
el.addEvent('click', function(e) {
this.getParent().onsubmit();
});
});
});
</script>
</head>
<body>
<form method="post" onsubmit="alert('hi');" class="form">
<input type="text" value="test" />
<span class="submit">Submit the form</span>
</form>
</body>
</html>
You might want to try this code instead as it will check to see if the onsubmit event has been attached as an event listener rather than being a hard encoded attribute. If the event was attached as a listener the [form element].onsubmit() part won't work.
function myOnSubmit(formId){
var f = document.getElementById(formId);
if(document.createEvent){
var e = document.createEvent('Event');
e.initEvent('submit',true,false);
f.dispatchEvent(e);
} elseif(document.createEventObject){
var e = document.createEventObject('Event');
e.button = 1;
f.fireEvent('onsubmit',e);
} elseif(typeof(f.onsubmit) == 'function'){
f.onsubmit();
}
}