I have an application running with jquery-1.5.2.min.js. It works fine in IE9, 8, 7, FF and Chrome.
But there's this problem. I have a JavaScript function in a custom .js file using jQuery that rules the behaviour of a hidden field. Whenever a button is clicked, the hidden field is turned into a jQuery Autocomplete control, and loads the Autocomplete information through an Ajax call. The function is like this:
$.ajax({
type: "POST",
url: action,
dataType: "json",
data: "{type: '" + control + "', param:" + params + "}",
contentType: "application/json; charset=utf-8",
success: function (data) {
var dataTable = data;
$(selector).autocomplete({
minLength: 2,
source: dataTable,
open: function (e, ui) {
var options = $(this).data('autocomplete');
options.menu.element.find('a').each(function () {
var this_ = $(this);
var regex = new RegExp(options.term, "gi");
this_.html(this_.text().replace(regex, function (matched) {
return autocompleteTemplate.replace('%s', matched);
}));
});
},
focus: function (event, ui) {
$(selector).val(ui.item.label);
return false;
},
change: function (event, ui) {
if (!ui.item) {
var options = $(this).data('autocomplete');
var matcher = new RegExp("^" + $.ui.autocomplete.escapeRegex($(this).val()) + "$", "i"),
valid = false;
options.menu.element.find('a').each(function () {
if ($(this).text().match(matcher)) {
valid = true;
return false;
}
});
if (!valid) {
if (control == "ProjectType") {
$('#selector').val("...");
$('#selector').attr('disabled', 'disabled');
$('#another.selector').val("");
}
// Remueve los valores inválidos.
$(this).val("");
$(selector).val("");
$(selector).data("autocomplete").term = "";
return false;
}
}
if (control == "ProjectType") {
$('#selector').val("");
}
},
select: function (event, ui) {
$(selector).val(ui.item.label);
$(hidden).val(ui.item.value);
if (control == "ProjectType") {
Autocomplete("ProjectSubType", action, ui.item.value);
// This is a function that changes the CSS for another HTML control
ProjectSubType(false);
}
return false;
}
});
}
});
So, whenever I change the browser type from IE8 to IE7 or IE9, or from IE7 to IE8 or IE9, after activating this field, the following exception is thrown from jquery-1.5.2.min.js
Runtime error from Microsoft JScript: Cannot get value of property
'type': the object is null or undefined
FYI:
The AJAX calls work. The autocomplete works properly and fires the events it has to fire when completed, in the order they have to be fired.
There is another control that fires another AJAX event (filling a jqGrid) which produces no mistake.
The conditional clause that you see in the code, "if (control == "ProjectType")", is meant to allow another control to turn into an Autocomplete if this control being used has an Autocomplete option filled in. Otherwise, it is disabled, as you can see (I changed its name to '#selector'). This also works properly: if you fill in a value in that Autocomplete, the other control is filled with the options needed.
Thanks
UDP
The function that calls the AJAX function is the following:
function SetSearchMenu(url, local) {
$('#advancedSearch').hide();
$('#advSearch').click(function () {
if ($('#advancedSearch').css("display") == "none") {
$('#advancedSearch').show();
$('#generalSearch').val("...");
$('#generalSearch').attr('disabled', 'disabled');
ProjectSubType(true);
}
else {
$('#dAdvancedSearch').hide();
$('#General').val("");
$('#General').removeAttr('disabled');
}
if (alreadyOpen == false) {
Autocomplete("SelectorOne", url, null);
Autocomplete("ProjectType", url, null);
Autocomplete("Selector", url, local);
alreadyOpen = true;
}
});
}
The parameters url and local are sent from the $(document).ready() function, and are filled with an #Url.Action() in string format and another variable hardcoded to one.
Related
$("#destination1" + countVar).autocomplete({
minLength : 3,
source : function(request, response) {
var url = configOptions.icaocodeUrl;
var term = request.term;
url=url+term;
console.log(url);
$.ajax({
url : url,
type : "GET",
data : request,
dataType : "json",
success : function(data) {
response(data.slice(0, 10));
//alert(data);
},error: function(xhr, textStatus) {
alert('error');
}
});
},
change:function(event,ui){
console.log("fired in dest2");
},close:function(event,ui){
console.log("close in dest2"+'#dof1'+countVar);
console.log(countVar);
$(this).parents('form').find('#dof1'+countVar)
.filter(function () { return $(this).val() === ''; })
.first().focus();
}
});
above is my code for autocomplete and autotab(autofocus) to next field for dynamically created elements.autotab(autofocus ) is working fine for normal html but it is not working for dynamically created elements only.
Are you trying to focus() on a tab that is being dynamically added? If so, you might be triggering focus() to soon and the DOM element might not be there.
Try wrapping the focus function into a setTimeout() function to test it out.
setTimeout(function () {
$(this).parents('form').find('#dof1'+countVar)
.filter(function () { return $(this).val() === ''; })
.first().focus();
}, 2000); // 2 seconds
Using tutorials found i'm currently loading new pages with this:
$("a.nav-link").click(function (e) {
// cancel the default behaviour
e.preventDefault();
// get the address of the link
var href = $(this).attr('href');
// getting the desired element for working with it later
var $wrap = $('#userright');
$wrap
// removing old data
.html('')
// slide it up
.hide()
// load the remote page
.load(href + ' #userright', function () {
// now slide it down
$wrap.fadeIn();
});
});
This loads the selected pages perfectly, however the pages have forms that themselves use ajax to send the following:
var frm = $('#profileform');
frm.submit(function (ev) {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
alert(data)
}
});
However this is not sending the form as it did before the page itself was called to the parent page via ajax. Am I missing something? Can you not use an ajax call in a page already called by ajax?
I also have other issues, for example I disable the submit button unless there are any changes to the form, using:
var button = $('#profile-submit');
var orig = [];
$.fn.getType = function () {
return this[0].tagName == "INPUT" ? $(this[0]).attr("type").toLowerCase() : this[0].tagName.toLowerCase();
}
$("#profileform :input").each(function () {
var type = $(this).getType();
var tmp = {
'type': type,
'value': $(this).val()
};
if (type == 'radio') {
tmp.checked = $(this).is(':checked');
}
orig[$(this).attr('id')] = tmp;
});
$('#profileform').bind('change keyup', function () {
var disable = true;
$("#profileform :input").each(function () {
var type = $(this).getType();
var id = $(this).attr('id');
if (type == 'text' || type == 'select') {
disable = (orig[id].value == $(this).val());
} else if (type == 'radio') {
disable = (orig[id].checked == $(this).is(':checked'));
}
if (!disable) {
return false; // break out of loop
}
});
button.prop('disabled', disable);});
However this also doesn't work when pulled to the parent page. Any help much appreciated! I'm really new to ajax so please point out any obvious mistakes! Many thanks in advance.
UPDATE
Just an update to what i've found. I've got one form working by using:
$(document).on('mouseenter', '#profile', function() {
However the following:
$(document).on('mouseenter', '#cancelimage', function() {
$('#cancelimage').onclick=function() {
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
} }; });
Is not working. I understand now that I need to make it realise code was there, so I wrapped all of my code in a mouseover for the new div, but certain parts still don't work, so I gave a mouseover to the cancel button on my image form, but when clicked it doesn't do any of the things it's supposed to.
For anyone else who comes across it, if you've got a function name assigned to it, it should pass fine regardless. I was trying to update it, and there was no need. Doh!
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
};
Works just fine.
I have the following setup:
A document can have multiple forms.
When the input on an input field changes, jQuery will fire an ajax event. And input.data("checking", true) is called.
When the ajax event has been finished, input.data("checking", false) is called.
Now I want to make a custom form submit that waits for all input in this form to be on input.data("checking") === true.
My code so far, without the question applied:
$(document).on("submit", "form", function(event) {
event.target.checkValidity();
event.preventDefault();
event.stopPropagation();
//TODO: prevent this when not everything is checked
var dataSerialized = $(this).serialize();
var service = $(this).attr("action");
$.ajax({
url: "services/" + service + ".php",
data: dataSerialized,
type: "POST",
cache: false,
success: function(html) {
if (html == "1") {
//TODO: load page from json callback
//loadPage(onsuccess);
}
else {
loadPage("error");
}
},
error: function(html, message) {
finalError(message);
}
});
});
How could I make this function wait (non-blocking!) until all ajax events are finished?
Suppose to create a function checkDone which returns true when input.data("checking") == false for all input in the form, you could do:
$(document).on("submit", "form", function(event) {
event.target.checkValidity();
event.preventDefault();
event.stopPropagation();
var that = $(this);
var interval = setInterval(function() {
if(checkDone(that)) {
clearInterval(interval);
var dataSerialized = that.serialize();
var service = that.attr("action");
$.ajax({
url: "services/" + service + ".php",
data: dataSerialized,
type: "POST",
cache: false,
success: function(html) {
if (html == "1") {
//TODO: load page from json callback
//loadPage(onsuccess);
}
else {
loadPage("error");
}
},
error: function(html, message) {
finalError(message);
}
});
}
}, 500);
});
In this way you check every 0.5 seconds if you can submit the form after all inputs are validated, and if so the interval is cleared and the form submitted.
However I would recommend not to remove standard server side validation on post submit.
Reviewed many similar questions on stackoverflow.com (also on other resources), but found no answers. So I simplified and generalized questions. It seems like the obvious solution:
$(document).ready(function() {
var a = 3;
var b = 5;
// no message when pressed submit button
$('form').submit(function() {
$(window).off('beforeunload');
});
// confirm of the need to save
$(window).on('beforeunload', function(e) {
if (a != b)
if (confirm('You changed data. Save?')) {
$('form').submit();
// alert('Your data is saved. (With alert submit() work only in FireFox!?)');
}
});
});
But not submit work. If you use the alert(), it works only in FireFox. I would like to correct (possibly without delay) cross-browser solution. Maybe who knows radically another method solution.
P.S. On some originality beforeunload described here in the first part: https://stackoverflow.com/a/6065085/1356425, but this is not the solution obvious functional.
Chrome and Firefox blocking submits after the onbeforeunload-event. You have to use
$(window).on('beforeunload', function(e) {
if (a != b)
return 'You\'ve changed the data. Leave page anyway?';
}
});
I used synchronous AJAX (JAX) request and run handler for events onUnload or onBeforeUnload once for the respective browser. This solution has a single and almost cross-browser behavior.
Example (on jsfiddle):
$(document).ready(function() {
var form = $('form');
var textareas = $('textarea');
function array_compare(a_0, a_1) {
if(a_0.length != a_1.length)
return false;
for(i = 0; i < a_0.length; i++)
if(a_0[i] != a_1[i])
return false;
return true;
}
var flag = false; // flag to control the execution of the unloadHandler() once
var a_open = []; // array with data before unload
$('textarea').each(function(index) {
a_open.push($(this).val());
});
function unloadHandler() {
if (flag)
return;
var a_close = []; // array with data during unload
$('textarea').each(function(index) {
a_close.push($(this).val());
});
if (!array_compare(a_open, a_close)) {
if (confirm('You changed the data, but not saved them. Save?')) {
$.ajax({
type: 'POST',
url: '/echo/json/',
async: false,
data: form.serialize()/* {
json: JSON.stringify({
text: 'My test text.'
}),
delay: 3
} */,
success: function(data) {
if (data) {
console.log(data);
alert('All data is saved!');
}
}
});
}
}
flag = true;
}
// For FireFox, Chrome
$(window).on('beforeunload', function () {
unloadHandler();
});
// For Opera, Konqueror
$(window).unload(function() {
unloadHandler();
});
// Without message when pressed submit button
$('form').submit(function() {
$(window).off('beforeunload');
$(window).off('unload');
});
});
Best way to submit data on unload is to store it in localstorage and send it next time when any other page under same origin is requested.
function sendBeacon(data) {
data?dataArr.push(data):'';
for (var i = 0, len = dataArr.length; i < len; i++) {
$.getScript(dataArr[i], (function (index) {
dataArr.splice(index, 1) //Updata dataArray on data submission
}(i)))
}
}
$(window).on('beforeunload', function () {
localStorage.setItem('dataArr', JSON.stringify(dataArr));
})
var dataArr = JSON.parse(localStorage.getItem('dataArr'));
if (!dataArr) {
dataArr = []; // Create Empty Array
} else {
sendBeacon(dataArr); //Submit stored data
}
I'm using typeahead to pull names and then updating a hidden field with the id respective to the name. In my form the name can be left blank, filling it is not a requirement.
Is there a way to add custom error checking to the typeahead function? for instance, I start filling out the form and type/select a user, then I change my mind and want to leave it blank. by this point, the user id is already added to the hidden field, so even if i leave the name field blank, the form will be passed with the user id in it.
I guess I can always do error checking on submit, but am curious if there is a way to add to the native api.
my code is:
$('#name_field').typeahead({
minLength: 3,
source: function (query, process){
$.get('/url/getsource', {query: query}, function (data) {
names = [];
map = {};
$.each(data, function (i, name) {
map[name.uName] = name;
names.push(name.uName);
});
process(names);
});
},
matcher: function (item) {
if (item.toLowerCase().indexOf(this.query.trim().toLowerCase()) != -1) {
return true;
}
},
sorter: function (items) {
return items.sort();
},
highlighter: function (item) {
var regex = new RegExp( '(' + this.query + ')', 'gi' );
return item.replace( regex, "<strong>$1</strong>" );
},
updater: function (item) {
selectedID = map[item].id;
$('#id_field').val(selectedID);
return item;
}
});
I was hoping I can add something like
$('#name_field').typeahead({
myCustom: function (){
if($('#name_field').val() == ''){
$('#id_field').val('');
},
rest,
of the,
function
});
You could bind a function to the blur event of the user field. So as soon as the user makes any changes to another form element if it is left blank you clear the typeahead field.
$('#user-field').blur(function (e) {
if(this.val() === ''){
$('#typeahead-field').val(''); // Clear typeahead
}
});