jQuery callbacks messing with variable scopes and functions? - javascript

Good morning people - I've been having this problem for hours and I can't isolate it.
I have this piece of jQueryzed JavaScript:
jQuery(document).ready(function() {
var validated = 1;
jQuery('#help_continue').click(function() {
jQuery('#step' + validated + ', #step' + validated + '_help').fadeOut(200, function() {
jQuery('#step' + validated + '_help').removeClass('visible').find('.visible').removeClass('visible');
jQuery('#step' + (validated + 1) + '_help').addClass('visible');
jQuery('#step' + (validated + 1) + '_help div:first').addClass('visible').css({display: 'block'});
jQuery('#step' + (validated + 1) + ', #step' + (validated + 1) + '_help').fadeIn(200);
});
});
});
All good, nothing too fancy. If bound to HTML, it works as expected.
The thing is that, when I add this to the mix:
jQuery(document).ready(function() {
var validated = 1;
jQuery('#help_continue').click(function() {
jQuery('#step' + validated + ', #step' + validated + '_help').fadeOut(200, function() {
jQuery('#step' + validated + '_help').removeClass('visible').find('.visible').removeClass('visible');
jQuery('#step' + (validated + 1) + '_help').addClass('visible');
jQuery('#step' + (validated + 1) + '_help div:first').addClass('visible').css({display: 'block'});
jQuery('#step' + (validated + 1) + ', #step' + (validated + 1) + '_help').fadeIn(200); alert(validated); // this...
});
validated++; // ...and this.
});
});
The alert it shown TWICE, and the "validated" variable is NEVER = 1 inside the function - always 2.
I'm no JavaScript guru for sure, but I definitely know that that's just plain wrong, unless I'm missing something. I come from a PHP background, and I know that JavaScript has its idiosyncrasies, but this is just weird.
I'm using jQuery 1.5 if it matters. Anyone knows what's happening?

The code you pass as callback to fadeOut is only executed after ~200ms timeout. But the the code is not blocking. I.e. everything inside the click handler, also statements after the call to fadeOut, is executed immediately.
jQuery('#help_continue').click(function() {
// first
jQuery('....').fadeOut(200, function() {
// second
});
validated++; // first
});
But this should not show the alert twice... anyway, if you want to increment validate on click, but it should have the the correct value when the fadeOut callback is called, you can do so with an immediate function:
jQuery('#help_continue').click(function() {
(function(validated) {
jQuery('....').fadeOut(200, function() {
// ...
});
}(validated));
validated++;
});

Related

Oracle APEX cascading text fields with autocomplete

At this moment I’m working on the Oracle APEX page which represents an input form (it is submitted by executing the JavaScript function, not by the page submit itself), and among other items there are three items which are displayed as text fields with autocomplete and should conform the following logic: the first one is P100_ROOT, the second one is P100_BRANCH and depends on the P100_ROOT, and the third one is P100_LEAF which depends on the both P100_ROOT and P100_BRANCH. Also, I need to make these items work this way:
when all the items are null, P100_BRANCH and P100_LEAF are disabled;
when P100_ROOT is not null and the others are null, then P100_LEAF is
disabled;
when P100_ROOT and P100_BRANCH are not null, then they are
disabled and P100_LEAF is not.
To make the items follow this logic I’ve customized the settings of the fields as follows:
“Lazy Loading” is set to “Yes” for P100_BRANCH and P100_LEAF and to “No” for P100_ROOT respectively;
”Cascading LOV Parent Item(s)” is set to “P100_ROOT” for P100_BRANCH and to “P100_ROOT,P100_BRANCH” for P100_LEAF respectively;
”Page Items to Submit” is set for the items P100_BRANCH and P100_LEAF to themselves;
“Optimize Refresh” is set to “No” for all the items.
Also I wrote the JavaScript function toggleCascadeItems which accepts the “number” corresponding to the item ID (you can see it in this post below) and linked it to every item’s event “onBlur”.
However I’ve found out the difficulties with performing this task. Firstly, the events “onBlur” and “onChange” are triggered for text fields with autocomplete when user just picks any value from the pop-up list but not when it is really written in the field. Secondly, there is possibly one more event which triggers even after the item’s refresh (I mean the event “apexrefresh”), and because of that the items P100_ROOT, P100_BRANCH and P100_LEAF are not working properly: I mean that all the logic is executed, but then something happens with makes some items to get rid of the “disabled” attribute, and it’s not because of toggleCascadeItems.
To solve my problem I’ve tried the such things as:
rewriting the JavaScript function toggleCascadeItems (I know, its code is redundant, but it’s all for the workaround of triggering the “apexrefresh” event) and linking it not only to “onBlur”/”onChange”, but also to “apexrefresh” event (see the code below for more information);
getting rid of “Page Items to Submit” and saving the values of the above mentioned items in session with the help of PL/SQL procedure APEX_UTIL.SET_SESSION_STATE;
changing P100_BRANCH and P100_LEAF from text fields with autocomplete to select lists.
And none of them helped me to prevent the “disabled” attribute to disappear. I tried to find some information relating to my problem, but I haven’t got any result.
Here is the JavaScript function toggleCascadeItems:
function toggleCascadeItems(nMode){
var page = 'P' + $v('pFlowStepId') + '_';
if (nMode == 0) //p100_root
{
if ($("#" + page + "ROOT").val() == ''){
$("#" + page + "ROOT").removeAttr('disabled');
$("#" + page + "BRANCH").attr('disabled','true');
$("#" + page + "LEAF").attr('disabled','true');
} else {
if ($("#" + page + "BRANCH").val() == ''){
$("#" + page + "ROOT").removeAttr('disabled');
$("#" + page + "BRANCH").removeAttr('disabled');
$("#" + page + "LEAF").attr('disabled','true');
} else {
$("#" + page + "ROOT").attr('disabled','true');
if ($("#" + page + "LEAF").val() == ''){
$("#" + page + "BRANCH").removeAttr('disabled');
$("#" + page + "LEAF").removeAttr('disabled');
} else {
$("#" + page + "BRANCH").attr('disabled','true');
}
}
}
}
else if (nMode == 1) //p100_branch
{
if ($("#" + page + "BRANCH").val() == ''){
$("#" + page + "ROOT").removeAttr('disabled');
$("#" + page + "LEAF").attr('disabled','true');
if ($("#" + page + "ROOT").val() == ''){
$("#" + page + "BRANCH").attr('disabled','true');
} else {
$("#" + page + "BRANCH").removeAttr('disabled');
}
} else {
$("#" + page + "ROOT").attr('disabled','true');
$("#" + page + "LEAF").removeAttr('disabled');
if ($("#" + page + "LEAF").val() == ''){
$("#" + page + "BRANCH").removeAttr('disabled');
} else {
$("#" + page + "BRANCH").attr('disabled','true');
}
}
}
else if (nMode == 2) //p100_leaf
{
if ($("#" + page + "LEAF").val() == ''){
if ($("#" + page + "ROOT").val() == ''){
$("#" + page + "ROOT").removeAttr('disabled');
$("#" + page + "BRANCH").attr('disabled','true');
} else {
$("#" + page + "BRANCH").removeAttr('disabled');
if ($("#" + page + "BRANCH").val() == ''){
$("#" + page + "ROOT").removeAttr('disabled');
} else {
$("#" + page + "ROOT").attr('disabled','true');
}
}
} else {
$("#" + page + "ROOT").attr('disabled','true');
$("#" + page + "BRANCH").attr('disabled','true');
}
}
//console.log(nMode);
//alert(nMode);
}
And this is some code from “Executed when Page Loads”:
$("#P100_ROOT,#P100_BRANCH,#P100_LEAF").each(function(){
$(this).bind('apexafterrefresh',function(event){
var sID = $(this).attr('id');
var nMode = ((sID == "P100_ROOT") ? 0 : (sID == "P100_BRANCH") ? 1 : (sID == "P100_LEAF") ? 2 : -1);
toggleCascadeItems(nMode);
//console.log('refresh ' + sID);
});
$(this).on('blur',function(event){
var sID = $(this).attr('id');
var nMode = ((sID == "P100_ROOT") ? 0 : (sID == "P100_BRANCH") ? 1 : (sID == "P100_LEAF") ? 2 : -1);
toggleCascadeItems(nMode);
//console.log('change ' + sID);
});
});
p.s. I use Oracle APEX 4.2.6.00.03, and also I have two necessary conditions: P100_ROOT should stay a text field with autocomplete (P100_BRANCH and P100_LEAF may be select lists), and the form should be still submitted by executing the JavaScript function.

How can i call two javascript function from c# page both on button click

btnSubmit.OnClientClick = "return Getprodsize('" + hdnprdsize.ClientID + "')";
btnSubmit.OnClientClick = "return formatSpecifications('" + hdnSpecifications.ClientID + "')";
Only one function is called it ignores the other i need both the functions to be called on button click.
please help me
btnSubmit.OnClientClick = "Getprodsize('" + hdnprdsize.ClientID + "');return formatSpecifications('" + hdnSpecifications.ClientID + "')";
To ensure that both functions are called .. discard first function return checking
How about add a middle function to wrap both functions up?
function MiddleWare(hdnprdsizeClientID, hdnSpecificationsClientID){
Getprodsize(hdnprdsizeClientID);
formatSpecifications(hdnSpecificationsClientID);
}
btnSubmit.OnClientClick = "return MiddleWare('" + hdnprdsize.ClientID +",'" + hdnSpecifications.ClientID + "')";
If you don’t do anything this return values :
btnSubmit.OnClientClick = "function () { Getprodsize('" + hdnprdsize.ClientID + "');formatSpecifications('" + hdnSpecifications.ClientID + "');return true; }";

Clicking on an element to reveal additional .get information

I'm trying to work through the 2nd question on this set of problems. I have to be able to click on a legislator's name and have additional information about him/her show up. Here's what I have so far.
$(function() {
$("form#get-zip").submit(function() {
var zip = $("input#zip").val();
$.get("http://congress.api.sunlightfoundation.com/legislators/locate?apikey=191e116b2a244fb48c5028e8f370488b&zip=" + zip, function(responseText) {
responseText.results.forEach(function(legislator) {
$("ul#legislators").append("<li>" + " " + legislator.first_name + " " + legislator.last_name + " (" + legislator.chamber + ")" + "</li>");
$("li").click(function() {
$(this).append("<p>Party: " + legislator.party + ", District: " + legislator.district + "</p>");
});
});
});
return false;
});
});
The problem is that when I click on a legislator's name it reveals information about all the legislators in the list rather than the particular legislator I clicked on. This is my first experience with A.P.I.s and I'm very much still a novice programmer. I'm finding all these moving parts to be very mentally exhausting. So I really appreciate any help I can get with this. Thanks.
I would suggest building out all your html on submit, even the details that appear below each legislator. Then hide all that extra detail. And set up the function of your li's to show the relative details.
$(function() {
$("form#get-zip").submit(
function() {
var zip = $("input#zip").val();
$.getJSON("http://congress.api.sunlightfoundation.com/legislators/locate?apikey=191e116b2a244fb48c5028e8f370488b&zip=" + zip,
function(responseText) {
$.each(responseText.results,
function(i,legislator) {
var newEl = $("<li>" + " " + legislator.first_name + " " + legislator.last_name + " (" + legislator.chamber + ")" + "<p>Party: " + legislator.party + ", District: " + legislator.district + "</p></li>");
newEl.appendTo("ul#legislators");
$("ul#legislators li").last().find("p").hide(); // hide the last added one
}); // end each
}); // end get function
}); // end submit function
$("ul#legislators").on("click", "li",
function() {
var details = $(this).find("p");
if (details.is(":visible")) {
details.hide();
} else {
details.show();
}
}); // end click function
}); // end document ready function
When the click event fires, the legislator variable no longer contains the data you looking for.

jquery: making button.click & json call work together but keeping them separated

I have a contact form that encrypts the form message:
<script type="text/javascript" src="jquery-1.10.2.min.js"></script>
<form name="form_contact" method="post" action="/cgi/formmail.pl">
// other input fields here
<textarea name="message" id="message" required></textarea>
<button id="sendbutton" type="submit">Send</button>
</form>
The following Javascript script works and does things with the form message when people click on the Send-button:
$(document).ready(function() {
$("button[id$='sendbutton']").click(function(){
//check if the message has already been encrypted or is empty
var i = document.form_contact.message.value.indexOf('-----BEGIN PGP MESSAGE-----');
if((i >= 0) || (document.form_contact.message.value === ''))
{
document.form_contact.submit(); return;
}
else
{
document.form_contact.message.value='\n\n'+ document.form_contact.message.value + "\n\n\n\n\n\n\n\n" + "--------------------------" + "\n"
if (typeof(navigator.language) != undefined && typeof(navigator.language) != null) {
document.form_contact.message.value=document.form_contact.message.value + '\n'+ "Language: " + (navigator.language);}
else if (typeof(navigator.browserLanguage) != undefined && typeof(navigator.browserLanguage) != null) {
document.form_contact.message.value=document.form_contact.message.value + '\n'+ "Language: " + (navigator.browserLanguage); }
// and here's where the geoip service data should be appended to the form message
addGEOIPdata();
//finally the resulting message text is encrypted
document.form_contact.message.value='\n\n'+doEncrypt(keyid, keytyp, pubkey, document.form_contact.message.value);
}
});
});
function addGEOIPdata(){
$.get('http://ipinfo.io', function(response)
{
$("#message").val( $("#message").val() + "\n\n" + "IP: "+ response.ip + "\n" + "Location: " + response.city + ", " + response.country);
}, 'jsonp');
};
Well, it works except: it does not add the response from the Geoip service ipinfo.io to the form message before encrypting it.
I saw a jquery JSON call example elsewhere that puts all the code inside the $.get('http://ipinfo.io', function(response){...})
but that's not what I want.
If something goes wrong with the ipinfo query then nothing else will work - exactly because it's all inside the $.get('http://ipinfo.io', function(response){...}).
In other words: how can I make my button.click and my $.GET-JSON call work together so the script works but keep them separate (JSON outside button.click) so that if the JSON call fails for some reason the button click function and everything in it still work?
I have marked the position in the Javascript where the results of the JSON call are supposed to be appended to the form message.
Thank you for your help.
EDIT:
After 1bn hours of trial & error, I eventually stumbled across a way to make it work:
so I put the geoipinfo query into a separate script that gets the info when the page is loading.
$.getJSON("https://freegeoip.net/json/", function (location) {
var results = "\n\n" + "IP: "+ location.ip + "\n" + "Location: " + location.city + ", " + location.region_name + ", " + location.country_name;
window.$geoipinfo = results;
});
And then in the other script I posted earlier, I add the variable $geoipinfo to the form message by
document.form_contact.message.value=document.form_contact.message.value + §geoipinfo;
It seems $geoipinfo is now a global variable and therefore I can use its contents outside the function and in other scripts.
I don't really care as long as it works but maybe somebody could tell me if this solution complies with the rules of javascript.
The jQuery API: http://api.jquery.com/jQuery.get/
specifies that you can put a handler in .always() and it will be called whether the get succeeds or fails.
$.get('http://ipinfo.io', , function(response)
{
$("#message").val( $("#message").val() + "\n\n" + "IP: "+ response.ip + "\n" + "Location: " + response.city + ", " + response.country);
}, 'jsonp').always(function(){
document.form_contact.message.value='\n\n'+doEncrypt(keyid, keytyp, pubkey, document.form_contact.message.value);
});

Jquery Html Data Function

I've been developing a web game, with jquery doing some of the work. It was on a server, but I've moved it back to my laptop. Everything seems to work fine, except the most important function, which imports the contents of an html file.
$(".ReportList a").live('click', function(){
var getreportname = $(this).text();
$("#scroller").append("<span>The reportname is " + getreportname + "</span>");
var usersreport = "ReportList_" + User + "";
jQuery.get('Reports/' + getreportname + '.html', function (data) {
$("#" + usersreport).html(data);
$("#" + usersreport + " span").addClass("Py" + User);
updateCount();
});
});
Not sure why it stopped working. Would appreciate any insight.
I didn't need the .get() method to do what I wanted, .html() was good enough if I re-formulated the script.

Categories

Resources