Simple jQuery function not picking up click function - javascript

I am having a go at my very first jQuery function. What needs to happen is that a form will be assigned to the function. When a user clicks on the submit button it needs to first do validation on each :input field within the the function.
I am assigning a form as the selector for my function:
$("form[name='form_name']").validator();
This then gets passed into the function and is assigned to a function property called "selected_form". Within my jQuery function I have another function which needs to wait for the submit button to be clicked, and after that it needs to iterate through all of the :input form elements and handle simple validation.
The issue now is:
a) Within my jQuery function I am making a call to return validate(); Validate then checks to see whether the button as clicked. I suspect that because the function is run and there was no button clicked, it continues and basically returns the validate() function back as false without doing any checks. I assume I will need to customize this to almost wait until the button is pressed, but I really have no idea how to do that.
b) $(selected_form+" :input").each(function() { ... } does not work as it appears to not be able to use that as a selected. I need to iterate through the "selected_form" property and select only the :input fields. Any assistance?
c) If you have any other suggestions or best practices for me regarding building a proper jQuery function please assist, this is my first attempt and I would rather learn the best practices now as appose to following my own ideas.
(function($) {
$.fn.validator = function(user_options) {
var default_options = {
exclusions: false,
rules: false,
submit_btn_name: 'event_form_submit'
};
var selected_form = this;
var selected_element = false;
var element_type = false;
var options = $.extend(default_options,user_options);
function validate() {
// Run only if form has been submitted: (this does not appear to work now, the form gets submitted without the return false;
$("input[type='"+options.submit_name+"']").click(function(event) {
event.preventDefault();
// The selector here appears to be wrong?
$(selected_form+" :input").each(function() {
// Individual element validation will happen here, for now I am just looking to log the element types :)
selected_element = this;
console.log(get_element_type());
});
return false;
});
return false;
};
function get_element_type() {
return element_type = element.type;
}
return validate();
}
})(jQuery);
// Run the validator:
$(document).ready(function() {
$("form[name='tepg_form_processor']").validator();
});

As jalynn2 and others have mentioned, my selector was incorrect. Fixed and working :)

Related

Return parent function from child function on click

How can I return a parent function from a child function on click? Here's an example code:
function returnFunction() {
var output = false;
$('a').click(function() {
output = true;
});
return output;
}
var result = returnFunction();
The result will always be false since the click hasn't happened at the time the code is being run. How could I make this work though?
My intention is to call pop-up dialogs, and I'd like to have all the logic inside one function that can easily be loaded - including the click events of a Confirm dialog box.
Elsewhere in scripts I'd be calling it this way for example:
// Menu click triggers the dialog
$('a').click(function(e) {
// The function displays the dialog and returns the click events of the dialog
var result = returnFunction();
// If result was false, we'll prevent the menu access, for example
if (!result) {
e.preventDefault();
}
});
I'm aware of the jQuery UI dialog plugin. But I'd like to achieve this without it for now.
Thanks.
An over-simplification of it is:
Everything stops (including scrolling and clicking on hyperlinks) while executing javascript. This means you cannot "pause" the script until someone clicks on a link.
The typical way of solving this is a callback function:
function my_callback(some, arguments) {
// you can do whatever in here: an ajax load, set a global variable, change some of the page, ...
console.log(some, arguments);
alert(some + " " + arguments);
}
function returnFunction(callback, param) {
var output = false;
$('a').click(function() {
callback(param, "world");
});
}
returnFunction(my_callback, "hello");
demo at http://jsfiddle.net/UnBj5/
EDIT:
I did mention global variables because they are an option, but they are typically bad style. Try to use other means if possible.
If you want more help with it, provide more details of what you are trying to do.
Try using parameters instead. Send a parameter to a function that shows your alert boxes, show a different pop-up alert depending on the parameter, what you are trying to do won't work because its basically a chicken-egg problem.

jquery beginner - function to initiate by time

I am a rookie in JS, have a problem understanding JQUERY semantics.
I have a function written for checking the content of a cell.
Problem: the function just starts when the cell loses focus, if I click Submit, the error shows first, then it will run the function.
I want the function to run even when I am inside the cell. How to do it?
Initiated by this:
$(".user_id").blur(function(){ validateUserId($('.user_id')); });
The function:
function validateUserId(reference) {
if ( 5 == $(reference).val().length ) {
$.get('index.php?user=' + $(reference).val(), function(data) {
if ( "error" == data ) {
$(reference).parent().parent().addClass('error');
alert('error');
} else {
$(reference).parent().parent().removeClass('error');
$(reference).addClass('valid');
$(reference).parent().parent().addClass('success');
}
});
} else {
alert('short');
$(reference).parent().parent().addClass('error');
}
}
$(".user_id").on('keyup', function(){
validateUserId($(this));
});
i would use the keyup event.
So everytime somebody types a key in your input cell, the function will be executed.
$(".user_id").on("keyup", function(){ validateUserId($(this)); });
I changed the $(".user_id"), you take the value from ,to $(this). Since you want the value of the field you did the keyup event on. (And not an other field, if there would be 2 fields with the same .user_id class.)
Try to bind function on focus event
$("input[submit]").click(function(e){
e.preventDefault();
var valid = validateUserId($('.user_id')); // maybe the function could return a boolean value too instead of just adding classes to the HTML part
if (valid) {
$("#your_form_id").submit(); // only if the input is valid, submit it
}
});
sidenote on your problem: if you click the submit button it will first trigger the submit action which may give you an error and then execute the blur() block of code
Here is a working demo http://jsfiddle.net/pomeh/GwswM/. I've rewritten a little the code to:
cache DOM selections into variables,
use jQuery methods chaining,
improve if conditions with tripe equal signs,
separated AJAX calls and application logic,
cache identical AJAX calls,
use jQuery deferred to hide the asynchronous aspect of the verification (linked to AJAX)
Hope that'll help :)

Find out if html form has changed

Using jquery I've added a change handler to a form.
This works when any input is changed BUT only if the user manually changes an input and not when some other code changes the input.
Is there any way to detect if a form has changed even if its inputs are changed by code?
Yes, there seems to be some confusion over this. In an ideal world you would expect the onchange event to happen whenever the inputs change but thats not what happens. I'm sure for good reasons to - maybe not.
One way I've overcome this obstacle is to capture the form state into a variable just after displaying it and then just before submitting it to check if the state has changed and to act accordingly.
An easy state to store is what the serialize function returns. An easy place to store the state is using the data functionality. Both serialize and data are available with jquery.
Of course you can use other different forms of state (some form of hash) or storage for this state (standard global variable for example).
Here is some prototype code:
If your form id is 'xform' then you can call the following code when the form has displayed:
$('#xform').data('serialize',$('#xform').serialize());
And then, when you need to check, for example just before a button submit you can use:
if($('#xform').serialize()!=$('#xform').data('serialize')){
// Form has changed!!!
}
You could wrap all this up into a copy & paste javascript snippet that will give you a formHasChanged() function to call wherever you need it (NOT TESTED):
$(function() {
$('#xform').data('serialize',$('#xform').serialize());
});
function formHasChanged(){
if($('#xform').serialize()!=$('#xform').data('serialize')){
return(true);
}
return(false);
}
But I'll stop here otherwise I'll create yet another jquery plugin.
Serializing the form is certainly an option, but it will not work if:
you want to know which fields have changed
it only needs to check a subset of the fields
dynamically adding or removing fields.
Fortunately, every form element has a default value associated with its object:
input, textarea : defaultValue
checkbox, radio : defaultChecked
select: defaultSelected
for ex: to ckeck if input or textarea has changed:
var changed = false;
$(":text,textarea").each(function(){
changed = this.value != this.defaultValue;
return !changed; // return if at least one control has changed value
});
This is easily achieved in JavaScript without jQuery. initChangeDetection() can be called multiple times:
function initChangeDetection(form) {
Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}
Test on JS Bin
For older browsers that don't support newer arrow/array functions:
function initChangeDetection(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
el.dataset.origValue = el.value;
}
}
function formHasChanges(form) {
for (var i=0; i<form.length; i++) {
var el = form[i];
if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
return true;
}
}
return false;
}
Not in a regular way.
You can change with input and then trigger the change event.
$('#inputId').val('foo').trigger('change');
or with this:
$('#inputId').val('foo').change();
Here is what i did (i found my solution using zaf's answer)
$("form").change(function() {
$(this).data("changed","true");
});
$("input[type='submit']").click(function() {
if($("form").data("changed") == "true") {
var discard = confirm("Some unsaved changes. Discard them ?");
if(!discard) return false;
}
});
Try onchange attribute
According to W3c it should trigger anytime the content of an element, the selection, or the checked state have changed.

jQuery form validation questions?

I am new to jQuery and javascript and I am used mainly to php. I am upgrading my site so it contains a little ajax to improve usability and to keep me busy!
I am using this simple little script I threw together for the login page. All works well at the minute but I have a couple of questions I'd like to ask!
$('#loginForm .submit').click(function(event) {
$('.error').hide();
event.preventDefault();
var errors = 0;
var loginEmail = $('#loginEmail').val();
var loginPassword = $('#loginPassword').val();
if (loginEmail.length == 0) {
$('#loginEmail').after('<div class="error"></div>');
errors++;
}
if (loginPassword.length == 0) {
$('#loginPassword').after('<div class="error"></div>');
errors++;
}
if (!errors) {
$('.submit').submit();
}
});
You will notice that the first line of code within the function is;
$('.error').hide();
Now in php I would normally use;
if (isset(........)) {
Is there a simliar way to do this in javascript as when the user first activates the function there will be no html with the class .error?
Also I am trying to add a new parameter to the function as well as the event parameter, how would I do this? I have tried the following?
$('#loginForm .submit').click(function(event, var) {
$('#loginForm .submit').click(function(event var) {
$('#loginForm .submit').click(function('event', 'var') {
And all seem not to work. Then again I am going by php, jQuery/javascript is not my strong point!
Thanks
Before performing an action, you can check if the function $() selected element by using the following syntax:
if ($('.error').length)
{
// actions
}
If the .error - div exists in the DOM by default and is just hidden, you can't just check the length of $('.error'), because even if it's empty, length will return 1.
You could do something like this:
if($('.error').html().length !== 0){
//do something
}
This will check the containing string of the error-div, so if it's empty, length will return 0.
Still I would recommend setting a boolean var. If errors occur, it gets set to false and you can check the var and you do not have to query for DOM-elements for such a simple task.
To your second question, try something like this:
$('#loginForm .submit').bind("click", {variable1: var}, handleSubmit);
function handleSubmit(event){
var passedVar = event.data.variable1;
}

Binding multiple events of the same type?

Firstly, is it possible? Been struggling with this one for hours; I think the reason my events aren't firing is because one event is unbinding/overwriting the other. I want to bind two change events to the same element. How can I do that?
As per request, here's the function I'm struggling with:
(function($) {
$.fn.cascade = function(name, trigger, url) {
var cache = {};
var queue = {};
this.each(function() {
var $input = $(this);
var $trigger = $input.closest('tr').prev('tr').find(trigger);
//$input.hide();
var addOptions = function($select, options) {
$select.append('<option value="">- Select -</option>');
for(var i in options) {
$select.append('<option value="{0}">{1}</option>'.format(options[i][0], options[i][1]));
}
$select.val($input.val()).trigger('change');
}
var $select = $('<select>')
// copy classes
.attr('class', $input.attr('class'))
// update hidden input
.bind('change', function() {
$input.val($(this).val());
})
// save data for chaining
.data('name', name)
.data('trigger', $trigger);
$input.after($select);
$trigger.bind('change', function() {
var value = $(this).val();
$select.empty();
if(value == '' || value == null) {
$select.trigger('change');
return;
}
// TODO: cache should be a jagged multi-dimensional array for nested triggers
if(value in cache) {
addOptions($select, cache[value]);
} else if(value in queue) {
$select.addClass('loading');
queue[value].push($select);
} else {
var getDict = {}
getDict[name] = value;
// TODO: use recursion to chain up more than one level of triggers
if($(this).data('trigger')) {
getDict[$(this).data('name')] = $(this).data('trigger').val();
}
$select.addClass('loading');
queue[value] = [$select];
$.getJSON(url, getDict, function(options) {
cache[value] = options;
while(queue[value].length > 0) {
var $select = queue[value].pop();
$select.removeClass('loading');
addOptions($select, options);
}
});
}
}).trigger('change');
});
return this;
}
})(jQuery);
The relevant chunk of HTML is even longer... but essentially it's a select box with a bunch of years, and then an <input> that gets (visibly) replaced with a <select> showing the vehicle makes for that year, and then another <input> that gets replaced with the models for that make/year.
Actually, it seems to be running pretty well now except for on page load. The initial values are getting wiped.
Solved the issue by pulling out that $select.bind() bit and making it live:
$('select.province').live('change', function() {
$(this).siblings('input.province').val($(this).val());
});
$('select.make').live('change', function() {
$(this).siblings('input.make').val($(this).val());
});
$('select.model').live('change', function() {
$(this).siblings('input.model').val($(this).val());
});
Sucks that it's hard-coded in there for my individual cases though. Ideally, I'd like to encapsulate all the logic in that function. So that I can just have
$('input.province').cascade('country', 'select.country', '/get-provinces.json');
$('input.make').cascade('year', 'select.year', '/get-makes.json');
$('input.model').cascade('make', 'select.make', '/get-models.json');
Yes that is possible.
$(…).change(function () { /* fn1 */ })
.change(function () { /* fn2 */ });
jQuery event binding is additive, calling .change a second time does not remove the original event handler.
Ryan is correct in jQuery being additive, although if you find there are problems because you are chaining the same event, beautiful jQuery allows another approach, and that is calling the second function within the first after completion of the first as shown below.
$('input:checkbox').change(function() {
// Do thing #1.; <-- don't forget your semi-colon here
(function() {
// Do thing #2.
});
});
I use this technique frequently with form validation, one function for checking and replacing disallowed characters input, and the second for running a regex on the results of the parent function.
Update to Post:
OK... You all are quick to beat on me with your negative scores, without understanding the difference in how we each view Mark's request. I will proceed to explain by example why my approach is the better one, as it allows for the greatest flexibility and control. I have thrown up a quick example at the link below. A picture's worth a 1000 words.
Nested Functions on One Event Trigger
This example shows how you can tie in three functions to just one change event, and also how the second and third functions can be controlled independently, even though they are still triggered by the parent change event. This also shows how programmatically the second and third functions can BOTH be tied into the same parent function trigger, yet respond either with or independently (see this by UNCHECKING the checkbox) of the parent function it is nested within.
$('#thecheckbox').change(function() {
$("#doOne").fadeIn();
if ($('#thecheckbox').attr('checked')) { doFunc2() }
else { doFunc3() };
function doFunc2() { $("#doTwo").fadeIn(); return true; }
function doFunc3() { $("#doTwo").fadeOut(); return true; }
$("#doThree").fadeIn();
});
I've included the third 'Do thing #3 in the example, to show how yet another event can follow the two nested functions as described earlier.
Forgive the earlier bad pseudocode originally posted first, as I always use ID's with my jQuery because of their ability to give everything an individual status to address with jQuery. I never use the 'input:checkbox' method in my own coding, as this relies on the 'type' attribute of an input statement, and therefore would require extra processing to isolate any desired checkbox if there is more than one checkbox in the document. Hopefully, the example will succeed at articulating what my comments here have not.
I am actually not sure exactly if you can bind two different change events. But, why not use logic to complete both events? For example...
$('input:checkbox').change(function() {
// Do thing #1.
// Do thing #2.
});
That way, you get the same benefit. Now, if there are two different things you need to do, you may need to use logic so that only one or the other thing happens, but I think you would have to do that anyway, even if you can bind two change events to the same element.

Categories

Resources