I have the following problem with Javascript.
I'm trying to add an "onsubmit" handler automatically (after the page has been loaded) to every form element in the page.
So I wrote this script:
window.onload=function(){
var formElements=document.getElementsByTagName("form");
for (var k=0;k<formElements.length;k++){
formElements[k].onsubmit=function(param){
return formValidator(param);
}(formElements[k]);
}
};
The formValidator function takes a form object as parameter, validates the content of the input and textarea elements inside the form and returns true or false as results of the validation.
In the HTML file of the page I have a form element without the onsubmit attribute (that should be inserted by javascript).
The problem is that it seems that the form is automatically validated when the page is loaded (even if the user doesn't submit the form). And then if the user starts to insert data in the form and clicks the submit button the validateForm function doesn't execute.
Any ideas?
Thank you.
You're calling your handler function, and assigning the result of calling it to onsubmit. (The (formElements[k]) after the function calls it.)
You need to refer to the function without calling it. One good way to do that in the general case is to use a builder function (but see below for why that general case probably doesn't apply here):
window.onload=function(){
var formElements=document.getElementsByTagName("form");
for (var k=0;k<formElements.length;k++){
formElements[k].onsubmit=buildHandler(formElements[k]);
}
function buildHandler(form) {
return function(){
return formValidator(form); // <== I'm guessing `formvalidator` takes the form
};
}
};
But there's no need to create a separate handler for each form. The way you're assigning the handler, this will be the form element, so just:
window.onload=function(){
var formElements=document.getElementsByTagName("form");
for (var k=0;k<formElements.length;k++){
formElements[k].onsubmit=handler;
}
function handler(){
return formValidator(this);
}
};
The thing about this being the element will be true when you assign functions to onxyz properties on DOM elements, when you use attachEvent (on IE), or when you use addEventListener (standard). It is not true if you call a function from onxyz attributes in the markup, e.g. onsubmit="foo()" (although you can use onsubmit="foo.call(this);" and it will be).
Related
I'm not a javascript/jquery coder, and not sure if what I'm trying to do is possible.
I have a html/php/ajax form that is updated an sql database as the user fills it out. As they fill the form, there is a progress bar ran by javascript/jquery that updates as the user types in the input. The start of the function looks like this:
$("#update input").keyup(function() {
This works great. My problem is when the page is reloaded. My code is pulling sql data from the database to fill the value of every input on the page that has a value so that a user can come back and completely the form later. When the user reloads the page, the only way for the script to activate is if the user types in an input field.
I thought I would fix the issue by changing the my initial javascript/jquery function with $(document).ready(function() . This caused the script to only run when the page was loaded and not when the form was being filled out. I need both the script to run on page ready, and when a user is typing in the input filled. Is there a way I can run both $(document).ready(function() AND $("#update input").keyup(function() { simultaneously? Or is there a better why to accomplish this? Thanks!
Let me know if I need to post more code.
Here's a generic approach attaching declared functions to events.
function handler (e) {}
element.addEventListener('click', handler);
You're free to call handler everywhere, also inside $(document).ready, or if there's no other code in your DOMReady handler, you can just pass a reference as an argument:
$(document).ready(handler);
In your specific case you most likely want something like this:
$(document).ready(function () {
function handler (e) {...}
handler();
$("#update input").keyup(handler);
});
If the handler function uses the event object (e in the example), in modern browsers it's also available as a global event object, or in jQuery, e.originalEvent. The object doesn't exist if there's no event fired, though, in that case you've to pass a fake event object, containing the provided properties, to the handler, if it is needed.
I have a list of divs, that have individual onclick functions.
The functions lead to http links that open in new windows. I can not rewrite the onclick functions before generating the site because it is a third party rss feed that is being generated based on a rss file. Now i walt to keep the individual links but do something else with them.
The chronology would be the following:
User clicks the element that has a prewritten onclick function.
The onclick functions is blocked from opening in a new page.
The link inside the onclick function is saved for further use.
A HTML5 audio element gets the link as a source.
I have so far tried to overwrite the onclick function. Yet I lose the http link in the process.
<div class="fw-feed-item-url"
onclick="window.open('http://www.example.com/podcasts/podcast_eposode3.mp3'
, '_blank')">
$(".fw-feed-item-url").click(function(){
var audioSrcNew = eval($('.fw-feed-item-url').attr('onclick'));
audioElement.src = audioSrcNew;
console.log(audioSrcNew);
$('.fw-feed-item-url').this.attr('onclick','alert("done"); return
false;');
});
In JavaScript, callbacks and event handlers should be executed in the order they were bound, and there is no way to alter that order. The code in the onclick attribute will be bound directly after creation of the element, and will thus be the first to be executed.
The only way to prevent this is to remove the attribute, either in the source or client-side by using jQuery's .removeAttr. So override the onclick event on page load like the following sample code.
<script>
$(document).ready(function() {
var $elements = $(".fw-feed-item-url");
// Iterate over elements
$elements.each(function () {
var $elm = $(this);
// Reference to onclick attribute value for future use
var onClick = $elm.attr("onclick");
console.log(onClick);
// Remove onclick attr and bind your own click event
$elm.removeAttr("onclick").click(function () {
//Own code comes here
alert("Whoa!!!! click worked!!");
})
});
});
Referenced from
How to decide execution sequence for Javascript and Jquery function
I dynamically create a form, but Func() is being called on page load, instead of on click
var addrow_f = document.createElement("form");
addrow_f.setAttribute('method',"post");
addrow_f.setAttribute('action',Func());
var submitelement = document.createElement('input');
submitelement.setAttribute("type", "submit");
submitelement.setAttribute("name", "dsubmit");
submitelement.setAttribute("value", "Submit");
AddChild(addrow_f, submitelement);
AddChild(addrow_masterContainer, addrow_f);
The action attribute just indicates to what target the form request shall be send to.
And: Since you pass the parameter with parenthesis () it will be executed immediately. If you want to pass functions as callbacks, you have to do this without parenthesis.
If you want to react on events, you have to add event listener like click on an element. So you probably want to add an click event on the submit button.
Therefore it exists a function called addEventListener available for elements. You can use it like this: submitelement.addEventListener("click", Func);
I've been binding submit events to forms, and ensuring that they do not break the form, using jQuery like this:
jQuery('form').submit(function(e){
var form = this;
e.preventDefault();
alert('1');
setTimeout(function() {
alert('2');
form.submit();
}, 1000);
});
This is all good and well, except, if for some reason a front end developer gave a child input of this form an id of ="submit", this breaks, as form.submit() throws a JavaScript error (In Chrome, 'Uncaught TypeError: Property 'submit' of object # is not a function').
You can see an example of that happening here: http://jsfiddle.net/q68ky/ (Here's the behavior if there's no <input id="submit">: http://jsfiddle.net/JpXzL/
Now, I know I can prevent this from binding on forms that have children with an id of 'submit' with jQuery('form').not(:has('#submit')).submit(), and the form will process just fine, but my binding will never fire for those forms.
So, the question: How can I safely bind this jQuery function to all forms, including those with <input id="submit">?
EDIT: Worth noting that this problem doesn't go away if I unbind the submit handler and then trigger a jQuery submit on jQuery(form).
The only way I can think of:
(function () {
var method;
window.submit = function (theForm) {
if (!method) {
method = document.createElement("form").submit;
}
method.call(theForm);
};
}());
Then call submit(theFormYouWantToSubmit).
You can see it in action here: http://jsfiddle.net/q68ky/2/
Edit: To provide some explanation as to what this does....
This method creates a new form element (document.createElement("form")), and stores a reference to the "submit" attribute of it (method = document.createElement("form").submit). Because this is a newly created form element, with no child nodes, we can guarantee that the "submit" attribute is actually the "submit" method we need, rather than a child node with an id/name of "submit".
We then use the call method (part of Function.prototype), which sets the context of the submit method to the form we want to submit, rather than the window object, which is what it would otherwise be on.
The rest of the gubbins in the snippet caches the submit method, so that all of this (albeit small) overhead does not take place every time you want to submit the form, and captures the cached method in a local scope, instead of holding it in the global scope and polluting the global namespace.
As this is actually a non-jQuery problem, here is a non-jQuery solution:
HTMLFormElement.prototype.submit.call(form);
DEMO
Reference: HTMLFormElement
Update: Access to the DOM prototypes is only possible in IE8+. (and that is probably the reason why jQuery does not use it).
#Matt's answer instead should work in any browser
In addition the problem I identified in my other answer, there is an open jQuery bug exacerbating the issue:
.SUBMIT() CAN FAIL IF SOMETHING HAS ID="SUBMIT"
If an element with an ID of submit
exists in a form, .submit() can fail.
It's important that this function (in
particular) work correctly.
http://bugs.jquery.com/ticket/1414
Instead of form.submit();, you need
$(form).submit();
This is because form is just the bare DOM element, while $(form) is the jQuery object. Calling form.submit() is trying to access the submit property of form. Since it doesn't have one, it's defaulting to the old-school behavior of getting the child element whose id is submit (hence the "is not a function" error).
The error occurs if a form element's name or id is 'submit'. It looks like it's an issue with jQuery.
I have a form with multiple fields, and each time the user changes a field the form is submitted (via hidden iframe), and the response is placed within an appropriate div on the page via a callback. The first time this works fine. But on each subsequent field change and submission, the response is shown in every div that has been filled with a response (so they all show the same thing, not the desired behavior).
Can anyone tell me why this is happening? It seems that there is some retention of the selectors that have been called before (since last page load)... but I'm not sure. Here's my code:
$(function ()
{
$('#ImageAddForm input').change(function (){
form = $('#ImageAddForm');
var fldDiv = $(this).parent().attr('id'); // eg Image11
var thDiv = fldDiv.replace('Image', 'Thumb'); // eg Thumb11
$(form).iframePostForm({
post : function (){
var msg = 'Uploading file...';
$("#" + thDiv).html(msg);
},
complete : function (response){
$("#" + thDiv).html(response);
$(':input', '#ImageAddForm').not(':hidden').val('');
}
});
form.submit();
});
});
I'm not familiar with that plug-in, but I have a suspicion about what might be causing your problem. You are attaching some functionality to your form with the plug-in inside of your change event. This means that on every change you are attaching again, which is likely to cause some problems. Two solutions suggest themselves:
1) If the plug-in has some kind of call to unbind or destroy itself, call that right before binding the plug-in to the form. This should prevent any weird behavior caused by multiple binding.
2) Better solution: bind the plug-in to the form outside your change event, and scope your variables (fldDiv, tdDiv) such that they will be accessible to both your change event (so that they can be modified based on what changed) and the functions used by the plug-in (for post and complete). This way you will only bind the plug-in once, but can still pass and receive different data based on what field changed.