Delayed response from jQuery (with some other odd artefacts) - javascript

I'm getting a mind-boggling response from jQuery that I'm hoping someone can help me with. I have a simple problem ... I'm setting the "value" of a HTML form's hidden field (aka, <input type='hidden'> when the form loads. I have a form with three hidden fields and two are working just fine. The third ... well here's the problem:
Once the form has completed loading (and yes it has loaded and is visible ... as indirect proof the previous two hidden fields have loaded and successfully been set by jQuery), I run the following code (just showing relevant snippet as this final field is a date set to "today"):
case "today":
SetFieldValue (targetElement , Date.today().toString("yyyy-MM-dd HH:mm:ss") );
console.log ('Setting ' + jQuery(targetElement).attr('id') + ' to "today": ' + Date.today().toString("yyyy-MM-dd HH:mm:ss") );
break;
The SetFieldValue is a little function I wrote to allow setting DOM elements regardless of what type it was. The code is follows:
function SetFieldValue ( domObject, value ) {
// as a safety function, check if a string representation of the domObject was passed in and convert it to a jQuery object if it was
if ( jQuery.type(domObject) === "string") {
domObject = jQuery(domObject);
}
if ( jQuery.inArray (domObject.prop('tagName').toLowerCase(),['input' , 'select' , 'textarea']) >= 0 ) {
console.log ("setting to value attribute: " + value);
domObject.attr('value',value);
console.log ("now set to: " + domObject.attr('value') + "(" + domObject.attr('id') + ")" );
} else {
console.log ("setting to html attribute");
domObject.html( value );
}
return domObject;
}
Please note the console.log messages as this is important in understanding the craziness of the problem. When I run this, here's what I get on the console:
Now I set a breakpoint at the last line of the "today" case statement (aka, on the "break;" line). Based on the console messages all is well. It appears the DOM element #activity-start_time has been set. Well here's where it gets weird.
The first thing I do is test the reference to "targetElement" and the first thing the debugger console give me is an empty array:
What? That's pretty odd. While I'm pondering that a few seconds pass and all of sudden it resolves itself to what I'd expect (I don't retype it into the console it simply changes from the empty set to what you see below):
Now that the targetElement is exactly as I'd expect I do a simple check with jQuery that the DOM element of #activity-start_time is reporting the same value. You can see the result above. It's precisely the same as targetElement except it HAS NOT got a value. What?!?
I'm at a complete loss. Any help would be greatly appreciated.
Ken
p.s. I will note that other people have suggested using .prop instead of .attr both seem to behave precisely the same.

I know I didn't provide enough context for people to really dig into this problem but I have in the end solved it. What was the issue? It was silly really ... isn't always? Anyway it was just a case of the DOM element in questions 'id' not beging unique. Grrr. It's always the obvious things that you then go onto overlook that get you in trouble.
Anyway, thanks for your patience and help.

Related

Setting attribute of HTML element only affects node, not actual element

I am having an infuriating problem which is produced by following code:
function setPeriodTimes(day, period, from, to) {
document.getElementsByClassName("day" + day)[0].children[period - 1].setAttribute("from", from)
document.getElementsByClassName("day" + day)[0].children[period - 1].setAttribute("to", to)
}
it doesn't throw an error, however, when using this function, then looking in the console with
document.getElementsByClassName("day" + 1)[0].children[1].getAttribute("to")
I get the expected result, however looking at the elements page in the dev toolbox, I don't see the updated attribute values.
It is rather annoying and is preventing me from continuing... any advice would be most appreciated.
Thankyou Jacob.

Syntax for reading checkbox state (checked / unchecked state) into a variable in Meteor

I have a form in a Meteor app with one checkbox and several text fields for each row of a dynamic table. OnClick, I'm trying to manually grab the data from each field and load up a dataObject that I'm passing to my server to handle. Everything works except for reading the value of the checkboxes.
I assume it's a silly syntax error; I've tried the syntax from other answers such as meteor retrieve true/false value from checkbox switchChange but no luck so far...
The really weird thing (to me) is that my code just halts when it hits the line where I'm trying to read the checkbox state... no error message, no log, nothing to help me debug... it just stops executing.
Here's my HTML:
<input type="checkbox" id="{{sku}}-include" checked={{isChecked}}>
(isChecked is a helper; I've verified that it's working correctly, as is the {{sku}} bit in the id attribute.)
Here's my JS:
var dataObject = {};
var fieldName = '#' + thisProduct.sku + "-displayName";
dataObject.nickname = instance.$(fieldName).val();
console.log("found displayName value: " + dataObject.nickname + " when looking for " + fieldName);
fieldName = '#' + thisProduct.sku + "-include";
dataObject.includeInReports = instance.$(fieldName).is(":checked").val();
console.log("found Include setting: " + dataObject.includeInReports + " when looking for " + fieldName);
The first set of JS lines work fine; that element is a text field.
The second set of lines simply dies at the point where I try to actually read the "checked" value.
(I've tried with and without the : in :checked; for some reason every example I've found uses the colon but I'm not clear on why.)
The logging shows me that the field names are being constructed properly... the execution just stops when it hits the is("checked").val() line.
Many thanks in advance for any suggestions!
Per #Shaded:
Changing .is("checked").val() to .prop("checked") works perfectly.
To restate; the correct Meteor syntax to read the checked state of a checkbox, by ID, and store in a variable is:
myVar = instance.$(fieldName).prop("checked");
Your is might not be working depending on your version of jQuery. Prior to 1.7 it would check things differently than in more recent versions.
From jQuery docs
Prior to jQuery 1.7, in selector strings with positional selectors such as :first, :gt(), or :even, the positional filtering is done against the jQuery object passed to .is(), not against the containing document. So for the HTML shown above, an expression such as $( "li:first" ).is( "li:last" ) returns true, but $( "li:first-child" ).is( "li:last-child" ) returns false. In addition, a bug in Sizzle prevented many positional selectors from working properly. These two factors made positional selectors almost unusable in filters.
However this means that your doing a lot more work than you need to to see if you have a checked checkbox.
Try using $(fieldName).prop("checked") instead and you should get a simple true or false based on the object you're looking at.

Parsing a string returned from ckeditor using javascript string methods

I am trying to get a certain area of data out from ckeditor. In order to do that I use the following code
function get_body_html(){
var email = CKEDITOR.instances['message'].getData();
var before_body = header_to + to + to_subject + subject + subject_body;
var s_index = email.indexOf(before_body)+before_body.length;
var e_index = email.indexOf(body_footer);
return email.substring(s_index,e_index);
}
For some reason that works when I do this on page load
CKEDITOR.instances.message.setData(header_to + to + to_subject+
subject + subject_body + body_text + body_footer);
get_body_html();
it works correctly and gives me the same string that is contained in body_text.
But when I do this
body_text = get_body_html();
CKEDITOR.instances.message.setData(header_to + to + to_subject + subject +
subject_body + body_text + body_footer);
in an onclick function it gets the wrong indexs somehow. Sometimes it can't find the string and returns -1 other times it just gets a weird index that doesn't make sense. These index variations only happen when my code is changed to tackle the problem a different way. So if it is the wrong indices like -5 and 2 then those would continue to be the wrong indices until I made a code change.
There are two facts that you should know about editor.setData.
In some cases it is asynchronous (it depends on the type of editor). That's why it also accepts a callback. Therefore any code that is meant to be executed after setData() should be executed in that callback.
It never is asynchronous before editor is ready. In this period (between editor initialization and instanceReady event) it works in a different mode - it just caches the set value and on getData() it returns exactly that value.
So, as I see on page load you call synchronously setData() and getData() - your function works because you get the value you're expecting to get.
But then, when you try to getData() when editor is already ready you get the HTML parsed, fixed, processed and perhaps differently formatted by CKEditor. I guess that your indexOf() checks are not enough to handle this. You have to rethink your function - e.g. regexp can help.
What also can help is removing htmlwriter plugin, which formats HTML in a way which may make it harder for you to work with it. E.g.:
config.removePlugins = 'htmlwriter';
I was able to get it to work. So the htmlwriter was one of the problems because it must add spaces in between by HTML tags. The other issue I found is that it strips some of the semicolons out in some of the style attributes. Overall CKEditor does a lot of formatting of the source which makes it very hard to index correctly but it's pretty much a trial and error thing. I ended up using the search JavaScript method for strings which can take a regular expression but I used it the same way indexOf would be used so I don't really know if that made a difference or not.

Whats happening? One day its OK, the next day its 'undefined'?

I am writing a greasemonkey script. Recently i had this same problem twice and i have no idea why is this happening.
function colli(){
.....
var oPriorityMass = bynID('massadderPriority');//my own document.getElementById() function
var aPriorities = [];
if (oPriorityMass) {
for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
var sCollNumber = oPriorityMass.childNodes[cEntry].getAttribute('coll');
if (bynID('adder' + sCollNumber + '_check').checked)
aPriorities.push(parseInt(sCollNumber));
}
}
.....
}
So the mystery of this is, one day i had oPriorityMass named as oPririoty. It was working fine, but the whole function was not yet complete and i started working on another functions for my script. These functions have no connection with each other.
Few days later i decided to go back to my function in the above example and finish it. I ran a test on it without modifying anything and got an error in the firefox's (4) javascript error console saying that oPriority.chilNodes[cEntry] is undefined. NOTE, few days back i have tested it exactly the same way and there was no such problem at all.
Ok, so, i decided to rename oPriority to oPriorityMass. Magically, problem got solved.
At first i thought, maybe there was some conflict of 2 objects, with the same name being used in different functions, which somehow continued to live even outside of function scope. My script is currently over 6000 lines big, but i did a search and found out that oPriority was not mentioned anywhere else but in this exact function.
Can somebody tell me, how and why is this happening? I mentioned same thing happened twice now and they happened in different functions, but the same problem node.childNodes[c] is undefined yet node is not null and node.childNodes.length show correct child count.
What is going on? How do i avoid such problems?
Thank you
EDIT: The error given by error console is
Error: uncaught exception: TypeError: oPriorityMass.childNodes[cEntry] is undefined
In response to Brocks comment:
GM_log(oPriorityMass.childNodes[cEntry]) returns undefined as a message. So node.childNodes[c] is the thing that is undefined in general.
My script creates a div window. Later, the above function uses elements in this div. Elements do have unique IDs and i am 100% sure the original site don't know about them.
My script has a start/stop button to run one or the other function when i need to.
I have been refreshing the page and running my script function now. I have noticed that sometimes (but not always) script will fail with the described error on the first run, however, if i run it again (without refreshing the page) it starts working.
The page has a javascript that modifies it. It changes some of it's element widths so it changes when the browser is resized. But i know it has no effect on my div as it is left unchanged when i resize browser.
EDIT2:
function bynID(sID) {
return top.document.getElementById(ns(sID));
}
function ns(sText) {
return g_sScriptName + '_' + sText;
}
ns function just adds the script name in front of the ID. I use it when creating HTML element so my elements never have the same id as the web page. So bynID() is simple function that saves some typing time when i need to get element by ID.
I have modified my colli() function to include check
if (oPriorityMass) {
if (!oPriorityMass.childNodes[0]) {
GM_log('Retrying');
setTimeout(loadPage,2000);
return;
}
for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
var sCollNumber = oPriorityMass.childNodes[cEntry].getAttribute('coll');
if (bynID('adder' + sCollNumber + '_check').checked)
aPriorities.push(parseInt(sCollNumber));
}
}
The loadPage function does 1 AJAX call, then i run few XPATH queries on it, but the actual contents are never appended/shown on the page, just kept inside document.createElement('div'), then this function calls colli(). So now, as i have modified my function, i checked the error console and saw that it may take up to 5 tries for it to start working correctly. 5 x 2seconds, thats 10 seconds. It is never 5 retries always, may vary There's got to be something else going on?
In Firefox, childNodes can include #text nodes. You should check to make sure that childNodes[cEntry] has nodeType == 1 or has a getAttribute method before trying to call it. e.g.
<div id="d0">
</div>
<div id="d1"></div>
In the above in Firefox and similar browsers (i.e. based on Gecko and WebKit based browsers like Safari), d0 has one child node, a text node, and d1 has no child nodes.
So I would do something like:
var sCollNumber, el0, el1;
if (oPriorityMass) {
for (var cEntry=0; cEntry < oPriorityMass.childNodes.length; cEntry++) {
el0 = oPriorityMass.childNodes[cEntry];
// Make sure have an HTMLElement that will
// have a getAttribute method
if (el0.nodeType == 1) {
sCollNumber = el0.getAttribute('coll');
el1 = bynID('adder' + sCollNumber + '_check');
// Make sure el1 is not falsey before attempting to
// access properties
if (el1 && el1.checked)
// Never call parseInt on strings without a radix
// Or use some other method to convert to Number
aPriorities.push(parseInt(sCollNumber, 10));
}
}
Given that sCollNumber seems like it is a string integer (just guessing but it seems likely), you can also use:
Number(sCollNumber)
or
+sCollNumber
whichever suits and is more maintainable.
So, according to your last edit, it now works, with the delay, right?
But when I suggested the delay it was not meant to do (even more?) ajax calls while waiting!!
NOT:
if (!oPriorityMass.childNodes[0]) {
GM_log('Retrying');
setTimeout(loadPage,2000);
return;
More like:
setTimeout (colli, 2000);
So the ajax and the other stuff that loadPage does could explain the excessive delay.
The random behavior could be caused by:
return top.document.getElementById(ns(sID));
This will cause erratic behavior if any frames or iframes are present, and you do not block operation on frames. (If you do block such operation then top is redundant and unnecessary.)
GM does not operate correctly in such cases -- depending on what the script does -- often seeming to "switch" from top scope to frame scope or vice versa.
So, it's probably best to change that to:
return document.getElementById (ns (sID) );
And make sure you have:
if (window.top != window.self) //-- Don't run on frames or iframes
return;
as the top lines of code.
Beyond that, it's near impossible to see the problem, because of insufficient information.
Either boil the problem into a Complete, Self Contained, Recipe for duplicating the failure.
OR, post or link to the Complete, Unedited, Script.

Server side variables in javascript

I suppose this isn't a huge deal, since there are other way around this issue, but I'm really curious as to the answer, since I thought this was possible to do.
I have a public property that returns a boolean in my code behind. I'd like to access this server variable in my javascript validation function, but so far, not quite getting it.
Public Property editMode() As Boolean
Get
If Cache("editMode") IsNot Nothing Then
Return (DirectCast(Cache("editMode"), Boolean))
Else
Return False
End If
End Get
Set(ByVal value As Boolean)
Cache("editMode") = value
End Set
End Property
function validateEdit()
{
alert("editMode value is " + '<%#editMode()%>');
if ('<%#editMode()%>'.toString() == "True")
{
alert("You are currently in edit mode. Please save or cancel changes.");
return false;
}
return true;
}
I've tried a bunch of variations on this, but it's always False. In the current code the alert returns "editMode value is False"
When I use:
if ('<%#editMode()%>') ...
Then it's still always False, but it goes into the if condition, so the behaviour is as if it were always true.
One other thing to mention is that most javascript/server tag stuff I find says to use <%=editMode %>, but I can't do this because every time I use the = instead of the # I get an exception:
"The Controls collection cannot be
modified because the control contains
code blocks (i.e. <% ... %>)."
So I solved this by using # and saying
Page.Header.DataBind()
Page.Form.DataBind()
In the page load event handler.
Any ideas? Thank you in advance. :)
(Also, I usually use C#, so I might have unknowingly done something goofy in the VB part, so feel free to point that out too)
First, try changing to this:
<%=editMode()%>
Not sure if that's it, but it can't hurt. Second, are you in edit mode when you first load the page? That code is going to run server side and return the result to the user.
On the user's page, they will see:
function validateEdit()
{
alert("editMode value is " + 'False');
if ('False'.toString() == "True")
{
alert("You are currently in edit mode. Please save or cancel changes.");
return false;
}
return true;
}
Again, not sure if that is it, but it is important to understand that javascript is not making any calls to the server.
This helped me fix the error.
"The Controls collection cannot be modified because the control contains code blocks"
Moving the javascript function out of the head and into the body fixes the problem. Seems to be a few things that could cause this issue, but in my case, the most likely culprit is the AjaxToolKit.
One more thing.
You do realize you are converting a string to another string with
'<%#editMode()%>'.toString()
Right?
I think what you want is this
if ('<% =editMode.toString() %>'= 'True')...
or Better yet
if (<% =editMode.toString().ToLower() %>)...

Categories