VBA IE call a javascript containing 'this' keyword - javascript

I am attempting to call a javascript function on a webpage that contains the 'this' keyword which is referring to the <input> textbox on the webpage. The function looks like this:
functiondostuff('hdnAttribute',this,'Key')
Using
js = "functiondostuff('hdnAttribute',this,'Key')"
Call IE.Document.parentWindow.execScript(js)
doesn't throw an error but does not produce the results of the function since this cannot be identified.
Stepping through the website this = [object DispHTMLInputElement] instead of the element name while the function is running. Anyone have any ideas?
Good Morning,
Adding more to this issue. There seems to be two problems, 1st is setting the window.event, functiondostuff begins with: if (window.event && window.event.keyCode == 13), when the function is called it exits out immediately due to the event being null. Is there a way to pass the event as 13 to the website? The second issue is submitting the "this" HTMLInputObject.
Does anyone know a method to fire the 'onkeypress' event? I am at the point of trying sendkeys to avoid calling the function but have not been able to get them to work with IE. Thanks for any suggestions!

Key point is context. If you have this HTML
<input onclick="functiondostuff('hdnAttribute',this,'Key')">
then the browser can infer context from the user interaction and set this for you correctly.
From within VBA that's a slightly different matter and you have to define context manually.
How about this:
Dim js As Variant
js = Array( _
"var input = document.getElementById('yourElementsId');", _
"functiondostuff('hdnAttribute',input,'Key');" _
)
Call IE.Document.parentWindow.execScript(Join(js, vbNewLine))
This way you get to define context yourself.
document.getElementById was just for the sake of the example. If your element has no ID, use any other method (like DOM traversal, document.querySelectorAll, document.getElementsByTagName + a loop, ...) to get a reference to the desired element.

Related

Javascript - Need an Underscore in Function Name?

I don't have any trouble with this code but I am very curious as to why the function below seems to need an underscore in its name.
function _clear()
{
document.getElementById("test").innerHTML = "";
}
The function _clear() only executes after clicking the button if the function name contains an underscore.
<button type="submit" onClick="_clear()">Clear</button>
According to the MDN, clear() is a method of the Document object, which one might call by writing document.clear(). But, since this method is deprecated one ought not to call it at all. In fact, in HTML5, the method does nothing (see HTML5 spec).
So, until this method is actually removed from the Document object, one might conclude that a potential conflict exists in having a user-defined function with the same name as that of the Document's method. That said, the following code runs just fine using Google Chrome (Version 49.0.2623.112 m):
var d = document;
d.g = d.getElementById;
function clear()
{
d.g("test").innerHTML = "";
}
var test = d.g("test");
test.onmouseover=clear;
See demo
It's unlikely that there is a conflict between clear() and document.clear(). I wrote a user-defined function that uses the same name as another document method and the code ran flawlessly; see here.
Apparently, when the onclick event attribute is given the user-defined function "clear()" there is some kind of confusion with clear() being associated with document.clear(); see here and read the excellent explanation in the official answer. In brief, the issue boils down to "...the Document object is in the scope chain before the Window object (...)" (see JavaScript: The Definitive Guide).
If for some reason you were determined for the code to work, here's how to specify the correct context:
HTML:
<div id="test">a test to see if this will clear</div>
<button id="but" onclick="window.clear()">Clear</button>
So, the user-defined function actually becomes a method of the Window object, along side the built-in ones like window.open(), allowing the code to execute; see here.
Note, the best way to have an action occur when a click event occurs is to put this line in your JavaScript code given a button with an id of "but":
but.addEventListener('click',clear);
See demo.
That's because clear() is a function that already exists in JavaScript. You could also add the underscore to the end or add another c or do anything so that the function has a different name.

Is attaching an onchange object a closure?

I have searched prior SO posts here, here and here, and couldn't an answer that made sense to me. This should be a basic question, but I'm not understanding the posts I find. They don't seem to address using a this parameter.
I want to programatically add an input with an onchange event, such that the final result is this:
<input type="button" onchange="handleButtonOnChange(this)">ClickMe</input>
I am working on a project that is using an embedded IE6 browser inside a old Delphi application, so I have to have a solution that is IE6 compatible (yes, IE6 is horrible, but there are reasons I am stuck with it for now).
My initial attempt was this:
var DaySelect = document.createElement("select");
DaySelect.id = ParentID+"-day";
DaySelect.disabled = true;
MonthSelect.onchange="handleDayChange(this);" //<--- not correct
Parent.appendChild(DaySelect);
I then read that the .onchange should be assigned an object, not a string, and one should use this instead:
MonthSelect.onchange=handleDayChange; //<--- '(this)' removed
But it seem to me that this will result in this element (notice the missing this parameter)
<input type="button" onchange="handleButtonOnChange">ClickMe</input>
If I use the line below, instead, won't this make a closure, and the 'this' will refer to the event at the time the object is assigned to the .onchange property, instead of being the event at the time of the change event?
//Does the line below make a closure?
MonthSelect.onchange=handleDayChange(this); //<-- What does 'this' refer to?
I'm a relatively new web programmer, but long time Delphi programmer. Closures still make my head hurt. I appreciate any help in this.
Also, I read here about using addEventListener and the problems with older versions of IE, and the last post on the page provides a work around. But I don't understand how it works.
EDIT -- And what about passing other parameters? It seems that many event handlers will need to have parameters specific for the attached element. It seems that it is just not possible to add a listener with any parameters.
A simple closure if you are creating the elements in JS as you show:
var DaySelect = document.createElement("select");
DaySelect.id = ParentID+"-day";
DaySelect.disabled = true;
MonthSelect.onchange=function(){handleDayChange(DaySelect);};
Parent.appendChild(DaySelect);
Since the function is created inside the scope that you create the element in, the same variables will be available to it.
EDIT:
Additional parameters can be passed with this method, for example, the anonymous function we create and attach as the handler will still have the event object sent to it:
function(e){handleDayChange(DaySelect, e);};
In the event object you will have access to the event target, but in your example the event target and "this" are not the same element, so there would be no way for the handler to know about the DaySelect element.
jQuery makes a lot of event handling much simpler which is one of the reasons many people use it, it also normalizes it's methods between various browsers so you don't have to write multiple versions of the same code (in most cases)

onkeyup or onkeypress javascript event issue - password status updates

Programming Question First (from w3 schools)
The programming example way below (from W3 schools) is nice and easy, it works on their website but I'm really confused on something.
onkeypress="return noNumbers(event)"
why is there a return before the function? What does it do? If you know the answer to that - how did you find out that information? My guess would be, that it allows the keypressed function to continue processing the keystroke since my event "interupted" it?
also - I have been trying to see what 'event' is. It doesnt seem to be a keyword. I spent > hour trying to find what it is. It doesnt seem to be assigned anywhere in their code example. Normally in that spot you would see 'this'. If it's a not assigned variable will it always pass the event handler? Confused...
What I want to do with their function
I want to make a password strength checker AS you type. I was looking at their example so I could figure out how to capture keys (cross browser and minimal IE7). My idea was...
<input type="password" name="pword" maxlength="50" size="50" id="field_pword" onkeyup="PasswordStrength(name, 8, 'relaxed')" onblur="CheckField(name, 8, 1)">
note: Yes, I know it's better to assign event handlers outside of the html but I couldn't see a way to pass variables to it unless it was inline. I'm a novice so I may have overlooked something but... thats why I do it IN the HTML.
also, IS IT BAD how I am passing name? it does send pword to the function but am I doing something wrong there? Should I just make it a constant string? It works as is, but sometimes just because something works... doesn't mean it's correct. :)
onkeyup="PasswordStrength('pword', 8, 'relaxed')" onblur="CheckField('pword', 8, 1)">
My checkfield function works (I use it after every field) I recently added in PasswordStrength. My question is... my new function isn't passing the event hander so how can I check what key is pressed? Can I do this?
onkeyup="PasswordStrength(name, 8, 'relaxed', event)"
or should it read...
onkeyup="return PasswordStrength(name, 8, 'relaxed', event)"
If I can't pass whatever 'event' is that way, inside my function can I accurately get what the key pressed was without a big mess of code? Since I'm learning I need examples to be as simple as possible (please).
Using my function I was going to do it this way but I still don't know how to get what key was pressed...
function PasswordStrength(sField, iMinLength, sStrength, e?)
{
var form = document.forms[0];
var gc = form[sField].value;
// once I have the value I can do checking but it would be nice to have WHAT key
// was pressed
// the e? above is where I was thinking of passing the event
W3 example I was pulling some knowledge from...
function noNumbers(e)
{
var keynum;
var keychar;
var numcheck;
if(window.event) // IE
{
keynum = e.keyCode;
}
else if(e.which) // Netscape/Firefox/Opera
{
keynum = e.which;
}
keychar = String.fromCharCode(keynum);
numcheck = /\d/;
return !numcheck.test(keychar);
}
</script>
<form>
Type some text (numbers not allowed):
<input type="text" onkeypress="return noNumbers(event)" />
</form>
</body>
</html>
As someone is typing I was going to change the text using innerHTML beside the password field to say, "Weak", "Ok", "Good", "Perfect" or something along those lines for the password status. I'd love to do it how google does it with a graphic to the left of the field but I don't know how to do that simply. lol.
Is my way fixable? Do you have a better way to do this that I don't know about? Much appreciated. Awaiting an infusion of wisdom...
Just to your first programming questions:
Your suggestion is right, to return a value inside of an event
lets you interrupt the action depending on the values content. Returning false inside onclick
will end in the click not to be done. So <a href="http://test.de"
onclick="return false;">linkname</a> wont link you to anything if
JavaScript is active.
event is simply a variable declared before it runs into the actual event, further explanation below.
You know the elements eventhandler attributes in JavaScript?
They are functions i.e.
document.createElement('div').onclick = function( event ){
//do something...
return true || false;
};
if you assign an onclick attribute to a tag it's simply another adjusted way to create this anonymous function. So
<input onclick="this.value = 'can\'t click me :P Mouse X: ' + event.clientX; return false;" type="text" id="ip" />
will behave as if you created an anonymous function taking the argument event.
window.onload = function(){
document.getElementById('ip').onclick = function( event ){
this.value = 'can\'t click me :P Mouse X: ' + event.clientX; return false;
};
};
This will behave exactly equal except of the delayed assignment.
The this keyword is always the owner object whose property function you're accessing or the object you're passing to an apply/call method. In this case it's obviously the owner - the DOM element. So this.value is the inputs value.
The event passed to the function is just an object containing some useful information about the current browsers state and miscellaneous. It's having slightly different properties filled with different values in different browsers but the main functionality is the same everywhere.
As explained above it makes no difference whether you write what you did or this:
window.onload = function(){
var yourElement = document.getElementsByTagName('pword')[0];
yourElement.onkeyup = function( event ){
PasswordStrength(this.name, 8, 'relaxed')
};
};
No it's not really bad to use just name.. whenever you access a property of the owners object you can omit the this keyword. Thus it's simply the same conflict as the one about writing
<script type="text/javascript">//<![CDATA[
onload = function(){ alert('hello!') };
//]]></script>
instead of window.onload or this.onload or even this.window.onload (which are all theoretically working since the everything containing object has a property named window which refers to itself). You could say it's a matter of convention. But since the convention to always access own properties over the this keyword (except for window which you should access over its property window) is strongly established and supported, you probably should write this.name.
That depends on whether you want to eventually interrupt the event and don't let the user finish his keyup. Explained above.
Why shouldn't you be able to pass the event object? Just treat it like a normal variable.
Combining the information above and the example in your question you should be able to get knowledge about which key was pressed.
1) The "return" word makes it so that if the function returns false, that gets passed back to the event and stops the keystroke from being processed by the browser (and appearing in the input field if that's what the event is on).
2) event is the Event object, which contains information on the event such as what key wa pressed, where the event was fired, etc.
3) Yes, it is bad how you are passing name, because you aren't passing it. Use this.name instead.
4) In this case, you don't need return because you aren't trying to stop a keystroke from being added to the textbox. Similarly, you don't need to pass event because you can pass this.value to get the contents of the textbox.
5) You can just pass this instead of this.name, this.value or whatever other values.Then, in the function, get the properties from the single argument.
6) Once you pass the entire value with this.value, you can run your tests on that. There is absolutely no need to know what key was pressed, especially as things like Ctrl+V would completely screw you over.
7) You can have a <div> and change its width and/or background colour to make a sort of strength bar indicator.

Manually creating a javascript event object

Say I have the following code:
$('#someid').click(function(event) { myFunction(event); });
function myFunction(event)
{
// do something with event
}
And I would like to test myFunction() with an eval statement, without doing something like using eval('$("#someid").click()');
Is there a way to manually create an event object in javascript that would work with an eval statement?
Also if myFunction is only used as an event handler, can it always assume event is not null?
Well, assuming that's JQuery at the top, the event object shouldn't ever be null.
The event object is a completely different critter between IE and everybody else so unless JQ 100% normalizes the object (I think it builds its own event object from the looks of it), it may still vary in properties that JQuery doesn't use between browsers. To manufacture your own event object I guess I would just use a for x in loop to see what's inside and build an object hash that simulates that.
So on this page something like:
$('#adzerk1').click( function(event){
console.log('fakeEvent = {');
for(x in event){ console.log( x + ':' + event[x] + ',\n')}
console.log('}');
} );
$('#adzerk1').click();
will return all properties and their values for that event in the console box of firebug. You'd have to make it recursive and test to get all the innards of properties of event that are objects themselves, however. Otherwise I've set it up so that all you would have to do is cut and paste the results into your JS and then delete the last comma before the closing curly bracket.

Is this right? A jQuery bug that erases the data store?

Fire up your firebug console and try this out.
Compare this:
$('body').data('x',1);
$(thisx).remove();
console.log($('body').data('x'));
to this:
$('body').data('x',1);
$(this.x).remove();
console.log($('body').data('x'));
Notice the difference? If thisx is undefined, it will immediatly throw a reference error. If x is an undefined property of this, jQuery will return the document as it's result set instead. Next jQuery will attempt to remove your document (which it can't), but before doing that it will remove all data attached to any child element of the document. Thus, wiping out your data store.
Note: this can be any element reference or object. You only need to have jQuery attempt to access an undefined property.
(Talk about a pain. It fails silently, and I'm trying to figure out why my data is suddenly missing. I track it down to a special case where an element reference was undefined in a specific situation.)
So on to my questions:
1) Before I submit a bug report, am I analyzing this correctly? Also if someone happens to know that this is a known issue, let me know. I couldn't find it in the bug tracker, but the interface isn't that great (or maybe I have this wrong).
2) Why is there ultimately any difference? I'm guessing thisx is evaluated immediately which causes the exception while this.x is a reference that is passed and evaluated in the called function, right? (where I think the line selector = selector || document; is the culprit.
3) Suggestions for how to handle this? I guess I should be checking that any/every element reference or property of an object (e.g. stored selector strings) is defined before I pass it to jQuery when removing something.
Why is there ultimately any difference?
Both thisx and this.x are evaluated when the function is called. The first one refers to an undefined variable name and this throws a reference error. The second one accesses an undefined property of an object, which results in the value undefined. This is just how javascript behaves in these cases.
Now when JQuery is called in the second case, the call $(this.x) evaluates to $(undefined) which is the same as if you just would have called $(). Since it looks to JQuery as if no argument was provided, it uses a default instead, and in this case the default is document. Then it proceeds trying to delete document, since it was effectively called as $().remove(), in which case this would be expected.
Suggestions for how to handle this?
The difference with the ReferenceError is a fundamental Javascript difference, not much that can be done about that. JQuerys behavior is unfortunate and a consequence of setting defaults by arg = arg||default. One could user arguments.length instead to get the real number of call parameters, but a change like this would surely result in lot's of broken code that relied on the default being used when undefined or 0 is passed, so it's unlikely to happen.
Try typing these into the console too (with no extra variables defined beforehand):
> a
ReferenceError: Can't find variable: a
> b = {}
Object
> b.a
undefined
one is a javascript error, one silently returns undefined (which jQuery will interpret as $() because javascript and jQuery can't tell the functions $() and $(undefined) apart)
this is the way javascript works, bug or feature I leave open to debate, but I don't think that this is jQuery's fault or problem.
edit: why does jQuery have $() defined?
From the docs:
By default, if no context is specified,
$() looks for DOM elements within the
context of the current HTML document.
If you do specify a context, such as a
DOM element or jQuery object, the
expression will be matched against the
contents of that context.
edit: the docs were referring to the context argument passed to $(), not to calling $() without arguments, so it isn't relevant here.
also note that
$().get(0) == $("").get(0)

Categories