Safari Native Code - javascript

Is anyone familiar with Native Code in OS X Safari (Version 3 and WebKit)? I'm using Javascript to parse some information in a form and one of my inputs is named "tags". When trying to get the value of that element using:
// button is being passed through a function as a DOM object
var tags = button.form.elements["tags"].value;
Safari returns some kind of function. I've gotten it to alert values like "function tags() { [native code] }" and Node Trees but I just can't understand why I would be having trouble. If anyone has a clue, please let me know. I've gotten it to work by changing the name of the input to something else and also by iterating through all elements and using if () statements to determine whether it's the element I want, but I'm awfully curious as to why Apple would restrict the use of any form element named "tags"...
P.S. - It's test and works fine in firefox.

[native code] just means that it's a function that is built in to the browser, rather than written in JavaScript. tags appears to be a WebKit extension to the DOM to allow you to get a list of elements in the form by tag name. For instance, if I run this on the StackOverflow page, I get the answer text area:
document.getElementById('submit-button').form.elements.tags("textarea")[0]
The issue is that an index into a collection in JavaScript also access any object properties (including methods), so when you try to access your named element tags, you get instead the method on the elements object that WebKit defines. Luckily, there is a workaround; you can call namedItem on the elements list to get an item by id or name:
var tags = button.form.elements.namedItem("tags").value;
edit: Note that its probably better to use namedItem in general even in other browsers, in case you need to retrieve an element named item or length or something like that; otherwise, if you use them as an index with the [] operator, you'll get the built in method item or length instead of your element.

Related

why is the elements in HTMLCollection is different from what HTMLCollection.item() returned in Chrome

I apologize if the title makes you confused. Let me explain that.
In Chrome dev tool, if I use, for example:
document.getElementsByClassName("login")
I get get an HTMLCollection which As you can see the 0-indexd property represents an typical Element object.
However, if I use
document.getElementsByClassName("login").item(0);
I got something like this:
As you can see this is not an element object. Instead, it is an HTML Div element(correct me if I named it incorrectly).
My question is that why item() method does not return the same object in the HTMLCollection? To my understanding, HTMLCollection is an object, what is retrieved from item() method is a property of the object, so they are supposed to be the same. Why is the result is unexpected?
Thank you!
This is just the Chrome console formatting the object in a "pretty" way:
By default, DOM elements are logged into the console as representation of their HTML
(From https://developers.google.com/web/tools/chrome-devtools/console/console-write#formatting_dom_elements_as_javascript_objects)
If you want to view the actual object, you can obtain a JavaScript representation of it with:
console.dir(document.getElementsByClassName("login").item(0))
(You can optionally drop the console.)
See: https://developers.google.com/web/tools/chrome-devtools/console/console-reference for info on the various console functions that are available.

Selenium - Universal Way to Convert "WebElement" to Javascript or JQuery Object

I have a a simple WebElement and I want to perform a series(one or more) of JS/JQuery type actions on my object.
Most of the time this is easy, I simply get the ID of the object, pass that into the "ExecuteScript" function, and viola works great:
RemoteWebDriver driver = ...;
var element = driver.FindElementByXPath("..."); //Or any other type of lookup
driver.ExecuteScript(#"$('#" + element.GetAttribute("id") + "')."DoSomeStuff...;");
20% this doesn't work at all because the item doesn't have an ID. Of course there are many ways to lookup items in Selenium and many ways to lookup items in jQuery or Javascript, but they don't always map, and while it may be possible to construct a query in jQuery that can lookup a Selenium object, that methodology cannot be the same for every object type.
Searching around it seems most people use the "id" method(Examples: 1, 2, 3). You can do this the opposite way. Another idea would be to give each element a unique ID in selenium before accessing it in jQuery, but it doesn't look like that would work because to set it you need to using Javascript or jQuery.
I've yet to find a way to do this Universally for every element, how can this be done?
You can, and always have been able to, pass element references back and forth in JavaScript via ExecuteScript. Whether those raw DOM elements can be converted to be used by JQuery is a matter upon which I am not qualified to speak. Nevertheless, the code for referencing a WebDriver-found element in your JavaScript code would be something like this:
// Assume element holds a reference to an already-found
// IWebElement, found using the standard WebDriver FindElement
// methods, and that driver is a properly-instantiated
// IWebDriver object.
// N.B., doing proper casting here, since it's idiomatic in
// the WebDriver library to code to the interface, not the concrete
// implementation.
IJavaScriptExecutor executor = driver as IJavaScriptExecutor;
executor.ExecuteScript("alert(arguments[0].tagName);", element);
The above code will throw up an alert (and block your Selenium code), showing the element's tagName JavaScript property. You can use this technique to use the element just as you would in JavaScript in the page.

Why no error when accessing a DOM element that doesn't exist?

I have some divs with partial views in them. Why would a reference to a div that doesn't exist not show some kind of error? For example, I only have one taskN div right now:
<div id="task1">
#Html.Partial("~/Views/PartialViews/TaskDosCommand.cshtml")
</div>
This is my jQuery to show the div:
$('#task' + task.PrestoTaskType).show();
When task.PrestoTaskType is 1, the task1 div correctly displays. However, when task.PrestoTaskType is anything but 1, like 2, then nothing displays (which is good), but there is no error; no error shows on the web page, and nothing displays in the Chrome developer tools console:
Shouldn't some kind of error display when accessing a DOM element that doesn't exist?
No, because what jQuery does is .show() all elements that the jQuery object wraps. If that's no elements at all, then so be it.
That's precisely a monad-like aspect of jQuery that makes it so useful: imagine the code you 'd have to write if things didn't work that way:
var $whatever = $(...);
if ($whatever.length) $.doSomething();
This is simply worse: you need to introduce a variable (in order to avoid waste) and a conditional... for what gain exactly?
If you want to see what jQuery matched you can do that very easily with .length as above, perhaps also using .filter in the process.
One of the nice things about jQuery is that all jQuery elements return a collection, whether that is 0, 1, or many elements. This is convenient because you don't need to check the size of the collection or wrap it in an array yourself when you want to call methods on it (each for example doesn't break for 0-1 elements).
While what you're talking about is frustrating in this particular case, it is better for jQuery to work this way so you don't have to do those sorts of checks everywhere else.
If you want to branch code based on the existence of such an element, you can do this:
var task = $('#task' + task.PrestoTaskType);
if (task[0]) {
task.show();
} else {
// task not found
// take appropriate steps
}
The [0] accessor will return the first DOM element in the jQuery object or undefined if the jQuery object is empty. Since your jQuery object was constructed with an ID selector, it either contains exactly one DOM element or it's empty.

Why does JavaScript's getElementsByClassName provide an object that is NOT an array?

I'm trying to get a list in JavaScript (not using jQuery) of all the elements on the page with a specific class name. I therefore employ the getElementsByClassName() function as follows:
var expand_buttons = document.getElementsByClassName('expand');
console.log(expand_buttons, expand_buttons.length, expand_buttons[0]);
Note that I have three anchor elements on my page with the class 'expand'. This console.log() outputs
[] 0 undefined
Next, for kicks, I threw expand_buttons into its own array as follows:
var newArray = new Array(expand_buttons);
console.log(newArray, newArray.length);
This suddenly outputs
[NodeList[3]] 1
and I can click through the nodelist and see the attributes of the three 'expand' anchor elements on the page. It's also worth noting that I was able to get my code working in a w3schools test page.
It may also be of note that my use of document.getElementsByName actually does output (to the console) an array of elements, but when I ask for its length, it tells me 0. Similarly, if I try to access an array element using array_name[0] as normal, it outputs 'undefined', despite there clearly being an element inside of an array when I print the object to the console.
Does anybody have any idea why this might be? I just want to loop through DOM elements, and I'm avoiding jQuery at the moment because I'm trying to practice coding with vanilla JavaScript.
Thanks,
ParagonRG
It's not so much a JavaScript thing as it is a web browser thing. That API is supplied by a native object (the document object), and by the DOM spec it returns a NodeList object. You can treat a NodeList like an array, and it's similar, but distinctly different (as you've noticed).
You can always copy a NodeList to a new array:
var nodeArr = Array.prototype.slice.call(theNodeList, 0);
or in modern ES2015 environments:
var nodeArr = Array.from(theNodeList);
JavaScript always exists in some runtime context, and the context can include all sorts of APIs that provide facilities to JavaScript code. A web browser is one of those contexts. The DOM is specified in a way that's not especially partial to JavaScript; it's a language-neutral interface definition.
I guess the short version of this answer would be, "because it just does."
It doesn't return an array because the object it returns is "live", specifically it is a live NodeList:
In most cases, the NodeList is a live collection. This means that changes on the DOM tree are going to be reflected on the collection.

`clone()` not working in Internet Explorer 6

I was trying to clone an element and append it to another child with following statement of jQuery:
$(userListJId).clone().appendTo(tempOwnJString);
Where userListJId and tempOwnJString are the id's of elements.
The above line of code works fine in Internet Explorer 7 and higher versions of it but does not seem to be working in Internet Explorer 6.
What could be the possible reason?
I used clone() on IE6 and so that should not be the problem.
Maybe you are creatong invalid HTML and IE6 which is less permissive than IE7 complains about this.
Can you show us your code and also the version of jQuery?
It's funny you should ask this because I had a quite similar problem (though it affected IE7 and probably IE6).
Also, not sure if you have done something special (i.e. defining variables) but perhaps you should refer to the objects as $('#userListJId') instead of just the element name. Again, I can't see the rest of the code, so you may have already defined those variables outside the document.* scope.
Basically, in IE, certain attributes cannot be modified after the object is created, an example being the ID attribute.
The work around is to not clone the object, at least through .clone(), but to take the outer HTML of the object you wish to clone as a string and do a regex .replace() on the id attribute, and then append the modified HTML into tempOwnJString.
Another gotchya in IE, is that sometimes (usually?) when it parses the HTML, it doesn't wrap quotes around attribute values if they contain only alphanumeric characters, so be mindful of this in your regex pattern.
Here is an example of some code I used.
if ($.browser.msie === true)
{
//unfortunately jQuery doesn't have an outerHTML function, so this is a hacky work around
templateHTML = $("#activityTemplate").clone().wrap('<div>').parent().html();
newHTML = templateHTML.replace(/id\=\w+/ig, 'id='+jsonObj.ContactLogID);
$(newHTML).prependTo($("#activityContainer"));
// in case i need to refer to newly created object
clone = $("#"+jsonObj.ContactLogID);
}
Again I can't say for certain if this is the issue you're having but with the information you gave and without any debug info (which IE6 doesn't really provide anyway) this is the best guess.
Echoing what #Foxtrot said, you need to ensure you set the id on the cloned element or you'll freak IE6 out. Afterall, all browsers follow the standard that ids must be unique. Their behavior when you violate this varies. You are experiencing variation.
As a trivial example:
var clone = $(userListIJD).clone();
clone[0].id = 'somethingElse'; // use a formula here, as presumably this is run over and over
// proceed with appending the clone

Categories