Javascript to jQuery translation - javascript

I have just started studying jquery and javascript and have encountered a line of code that I dont know how to translate. Any help would be much appreciated. Id like to translate it from JavaScript to jQuery so that I can use classes.
Here are the lines of code.
var rgb = getAverageRGB(document.getElementById('try'));
document.body.style.backgroundColor = 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')';

You're mixing things up with that second line:
$('.post').css("background-color", 'rgb('+rgb.r+','+rgb.g+','+rgb.b+')');
And the jQuery way to find an element by its "id" value is
var rgb = getAverageRGB($('#try')[0]);
The $('#try') part creates a jQuery-wrapped list of nodes that match the selector, so in this case it'll be just one node. However, presuming that API expects a DOM node and not a jQuery wrapper, the trailing [0] extracts the raw DOM node from the jQuery wrapper.
Keep in mind that jQuery is JavaScript — we're not talking about two different languages.

Related

Javascript creating an HTML object vs creating an HTML string

Pretty simple question that I couldn't find an answer to, maybe because it's a non-issue, but I'm wondering if there is a difference between creating an HTML object using Javascript or using a string to build an element. Like, is it a better practice to declare any HTML elements in JS as JS objects or as strings and let the browser/library/etc parse them? For example:
jQuery('<div />', {'class': 'example'});
vs
jQuery('<div class="example></div>');
(Just using jQuery as an example, but same question applies for vanilla JS as well.)
It seems like a non-issue to me but I'm no JS expert, and I want to make sure I'm doing it right. Thanks in advance!
They're both "correct". And both are useful at different times for different purposes.
For instance, in terms of page-speed, these days it's faster to just do something like:
document.body.innerHTML = "<header>....big string o' html text</footer>";
The browser will spit it out in an instant.
As a matter of safety, when dealing with user-input, it's safer to build elements, attach them to a documentFragment and then append them to the DOM (or replace a DOM node with your new version, or whatever).
Consider:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = "<p>" + userPost + "</p>";
commentList.innerHTML += paragraph;
Versus:
var userPost = "My name is Bob.<script src=\"//bad-place.com/awful-things.js\"></script>",
paragraph = document.createElement("p");
paragraph.appendChild( document.createTextNode(userPost) );
commentList.appendChild(paragraph);
One does bad things and one doesn't.
Of course, you don't have to create textNodes, you could use innerText or textContent or whatever (the browser will create the text node on its own).
But it's always important to consider what you're sharing and how.
If it's coming from anywhere other than a place you trust (which should be approximately nowhere, unless you're serving static pages, in which case, why are you building html?), then you should keep injection in mind -- only the things you WANT to be injected should be.
Either can be preferable depending on your particular scenario—ie, if everything is hard-coded, option 2 is probably better, as #camus said.
One limitation with the first option though, is that this
$("<div data-foo='X' />", { 'class': 'example' });
will not work. That overload expects a naked tag as the first parameter with no attributes at all.
This was reported here
1/ is better if your attribubes depends on variables set before calling the $ function , dont have to concatenate strings and variables. Aside from that fact ,since you can do both , and it's just some js code somebody else wrote , not a C++ DOM API hardcoded in the browser...

jQuery - Raphael - SVG - selector based on custom data

I have assigned a custom data attribute to some circles added to the Raphael canvas as follows in a each() loop:
marker.data('transaction', transaction);
How do I find elements on the canvas that have the same transaction data value?
Currently I have the code:
var found = document.querySelectorAll("[transaction='" + current_transaction +"']");
Which should return a NodeList with the elements, but it doesn't work. To retrieve the data into a variable, it is as simple as var foo = marker.data('transaction'), but obviously, this doesn't work if I want to retrieve a NodeList of the elements.
Therefore, I want my selector to be look as follows, but I cannot work out the correct syntax:
var found = document.querySelectorAll("data('transaction' = 1)");
Any help would be much appreciated
Being that Raphael must support VML, it doesn't keep data in the DOM as is normal with html5 applications. If you want to store data in the dom you must access the html node and set the attribute there...
marker.node.setAttribute('data-transaction', transaction);
Then you can then query the elements with querySelectorAll. Keep in mind this will fail on < IE8.
If you want to keep older IE support I'd recommend writing a function that iterates over your markers and returns the Raphael object when mark.data("transaction") == transaction
I think the problem is that jQuery has no access to the SVG nodes. You have to try normal Javascript. The problem could be the compatibility with older browsers if you use querySelectorAll.
Look here: http://dean.edwards.name/jsb/behavior/querySelectorAll.html
and here: http://www.w3.org/TR/selectors-api/#queryselectorall
Possible solution:
Have a look in Raphael-Doc : http://raphaeljs.com/reference.html#Element.data

Is it possible to get jquery objects from an html string thats not in the DOM?

For example in javascript code running on the page we have something like:
var data = '<html>\n <body>\n I want this text ...\n </body>\n</html>';
I'd like to use and at least know if its possible to get the text in the body of that html string without throwing the whole html string into the DOM and selecting from there.
First, it's a string:
var arbitrary = '<html><body>\nSomething<p>This</p>...</body></html>';
Now jQuery turns it into an unattached DOM fragment, applying its internal .clean() method to strip away things like the extra <html>, <body>, etc.
var $frag = $( arbitrary );
You can manipulate this with jQuery functions, even if it's still a fragment:
alert( $frag.filter('p').get() ); // says "<p>This</p>"
Or of course just get the text content as in your question:
alert( $frag.text() ); // includes "This" in my contrived example
// along with line breaks and other text, etc
You can also later attach the fragment to the DOM:
$('div#something_real').append( $frag );
Where possible, it's often a good strategy to do complicated manipulation on fragments while they're unattached, and then slip them into the "real" page when you're done.
The correct answer to this question, in this exact phrasing, is NO.
If you write something like var a = $("<div>test</div>"), jQuery will add that div to the DOM, and then construct a jQuery object around it.
If you want to do without bothering the DOM, you will have to parse it yourself. Regular expressions are your friend.
It would be easiest, I think, to put that into the DOM and get it from there, then remove it from the DOM again.
Jquery itself is full of tricks like this. It's adding all sorts off stuff into the DOM all the time, including when you build something using $('<p>some html</p>'). So if you went down that road you'd still effectively be placing stuff into the DOM then removing it again, temporarily, except that it'd be Jquery doing it.
John Resig (jQuery author) created a pure JS HTML parser that you might find useful. An example from that page:
var dom = HTMLtoDOM("<p>Data: <input disabled>");
dom.getElementsByTagName("body").length == 1
dom.getElementsByTagName("p").length == 1
Buuuut... This question contains a constraint that I think you need to be more critical of. Rather than working around a hard-coded HTML string in a JS variable, can you not reconsider why it's that way in the first place? WHAT is that hard-coded string used for?
If it's just sitting there in the script, re-write it as a proper object.
If it's the response from an AJAX call, there is a perfectly good jQuery AJAX API already there. (Added: although jQuery just returns it as a string without any ability to parse it, so I guess you're back to square one there.)
Before throwing it in the DOM that is just a plain string.
You can sure use REGEX.

Getting jQuery to work with another library (XML parsing)

We are using jQuery to generate an XML fragment and then convert it to a string using the html() function. But as we just found out, and if anyone doesn't know, the html() JavaScript function as implemented in IE is broken, broken, broken. Basically, it capitalizes some tags, adds attributes to others "helpfully" (in our case, ), and generally doesn't do the Right Thing.
I would like to use something like this to generate the XML string instead:
http://www.stainlessvision.com/jquery-html-vs-innerxhtml
However, this library won't play nicely with jQuery out of the box, e.g.:
var $dummyRoot = $('<dummyroot/>'); // since html() doesn't generate the outer element
var $foo = $('<foo></foo>');
var $font = $('<font ></font >');
$foo.append($font);
$dummyRoot.append($foo);
var $s = innerXHTML($dummyRoot); // <-- Doesn't work
I think it wants a more W3C DOM-ish object.
How can I get jQuery to talk to this innerXHTML() function; or, alternatively, is there another function I can use (maybe something built into jQuery or a jQuery plugin))?
Edit: Follow up for DDaviesBrackett's question. I also have a "body" element in my XML; look how it picks up CSS styling (and not just a element).
Is there an unwritten rule to not generate XML inside the DOM whose elements have names like body, font, head, etc.?
var $dummyRoot = $('<dummyroot/>');
var $foo = $('<foo></foo>');
var $body = $('<body></body>');
var $font = $('<font></font>');
$body.append($font);
$foo.append($body);
$dummyRoot.append($foo);
var $s = innerXHTML($dummyRoot[0]);
// $s equals "<foo><body bottommargin="15" leftmargin="10" rightmargin="10" topmargin="15"><font size="+0"></font></body></foo>"
the jQuery object wraps its contents, but exposes them via an array indexer. What do you get when you use
var $s = innerXHTML($dummyRoot[0]);
instead of your example?
Is there an unwritten rule to not generate XML inside the DOM whose elements have names like body, font, head, etc.?
jQuery relies on the innerHTML property to parse a given piece of text and construct the DOM from that. It was never meant to parse or generate XML as colliding names can give totally unpredictable results depending on how the browser sees it.
See
jQuery won’t parse xml with nodes called option
How do I parse xml with jQuery?
Parse content like XML, with jQuery
I have given a similar answer for generating proper XML in fewer steps using a recursive approach. To create the following XML:
<foo>
<body>
<font></font>
</body>
</foo>
you would write:
Σ('foo',
Σ('body',
Σ('font', '')
)
);
Σ just looks cooler, but you can change the function name to whatever you want :)

node selection and manipulation out of the dom (What is jQuery's trick ?)

Hi I would like to do dom selection and manipulation out of the dom.
The goal is to build my widget out of the dom and to insert it in the dom only once it is ready.
My issue is that getElementById is not supported on a document fragment. I also tried createElement and cloneNode, but it does not work either.
I am trying to do that in plain js. I am used to do this with jQuery which handles it nicely. I tried to find the trick in jQuery source, but no success so far...
Olivier
I have done something similar, but not sure if it will meet your needs.
Create a "holding area" such as a plain <span id="spanReserve"></span> or <td id="cellReserve"></td>. Then you can do something like this in JS function:
var holdingArea = document.getElementById('spanReserve');
holdingArea.innerHTML = widgetHTMLValue;
jQuery will try to use getElementById first, and if that doesn't work, it'll then search all the DOM elements using getAttribute("id") until it finds the one you need.
For instance, if you built the following DOM structure that isn't attached to the document and it was assigned to the javascript var widget:
<div id="widget">
<p><strong id="target">Hello</strong>, world!</p>
</div>
You could then do the following:
var target;
// Flatten all child elements in the div
all_elements = widget.getElementsByTagName("*");
for(i=0; i < all_elements.length; i++){
if(all_widget_elements[i].getAttribute("id") === "target"){
target = all_widget_elements[i];
break;
}
}
target.innerHTML = "Goodbye";
If you need more than just searching by ID, I'd suggest installing Sizzle rather than duplicating the Sizzle functionality. Assuming you have the ability to install another library.
Hope this helps!
EDIT:
what about something simple along these lines:
DocumentFragment.prototype.getElementById = function(id) {
for(n in this.childNodes){
if(id == n.id){
return n;
}
}
return null;
}
Why not just use jQuery or the selection API in whatever other lib youre using? AFAIK all the major libs support selection on fragments.
If you wan tto skip a larger lib like jQ/Prototype/Dojo/etc.. then you could jsut use Sizzle - its the selector engine that powers jQ and Dojo and its offered as a standalone. If thats out of the question as well then i suppose you could dive in to the Sizzle source and see whats going on. All in all though it seems like alot of effort to avoid a few 100k with the added probaility that the code you come up with is going to be slower runtime wise than all the work pulled into Sizzle or another open source library.
http://sizzlejs.com/
Oh also... i think (guessing) jQ's trick is that elements are not out of the DOM. I could be wrong but i think when you do something like:
$('<div></div>');
Its actually in the DOM document its just not part of the body/head nodes. Could be totally wrong about that though, its just a guess.
So you got me curious haha. I took a look at sizzle.. than answer is - its not using DOM methods. It seems using an algorithm that compares the various DOMNode properties mapped to types of selectors - unless im missing something... which is entirely possible :-)
However as noted below in comments it seems Sizzle DOES NOT work on DocumentFragments... So back to square one :-)
Modern browsers ( read: not IE ) have the querySelector method in Element API. You can use that to get and element by id within a DocumentFragment.
jQuery uses sizzle.js
What it does on DocumentFragments is: deeply loop through all the elements in the fragment checking if an element's attribute( in your case 'id' ) is the one you're looking for. To my knowledge, sizzle.js uses querySelector too, if available, to speed things up.
If you're looking for cross browser compatibility, which you probably are, you will need to write your own method, or check for the querySelector method.
It sounds like you are doing to right things. Not sure why it is not working out.
// if it is an existing element
var node = document.getElementById("footer").cloneNode(true);
// or if it is a new element use
// document.createElement("div");
// Here you would do manipulation of the element, setAttribute, add children, etc.
node.childNodes[1].childNodes[1].setAttribute("style", "color:#F00; font-size:128px");
document.documentElement.appendChild(node)
You really have two tools to work with, html() and using the normal jQuery manipulation operators on an XML document and then insert it in the DOM.
To create a widget, you can use html():
$('#target').html('<div><span>arbitrarily complex JS</span><input type="text" /></div>');
I assume that's not what you want. Therefore, look at the additional behaviors of the jQuery selector: when passed a second parameter, it can be its own XML fragment, and manipulation can happen on those documents. eg.
$('<div />').append('<span>').find('span').text('arbitrarily complex JS'). etc.
All the operators like append, appendTo, wrap, etc. can work on fragments like this, and then they can be inserted into the DOM.
A word of caution, though: jQuery uses the browser's native functions to manipulate this (as far as I can tell), so you do get different behaviors on different browsers. Make sure to well formed XML. I've even had it reject improperly formed HTML fragments. Worst case, though, go back and use string concatenation and the html() method.

Categories