I'm trying to identify why I cannot get my code to work using JavaScript to wrap all of a specific elements inside a specific div. I've read posts like this one but don't understand why it won't work using the query selector.
So i have this HTML:
<div class='containerA'>
<p>random text</p>
</div>
<div class='containerA'>
<p>random text</p>
</div>
Jquery is loaded in the browser, so using a simple select in JS should work but it fails with the error message shown below:
document.getElementsByClassName('containerA')[0].wrap('<div></div>') // fails "document.getElementsByClassName(...)[0].wrap is not a function"
Also, looping through each element to apply to all using JS fails, presumably for the same reason as the first failure above:
// "el.wrap is not a function"
for (var el of els) {
el.wrap('<div class="testWrap"></div>');
}
// "els[i].wrap is not a function"
for (i = 0; i < els.length; i++) {
els[i].wrap('<div class="testWrap"></div>');
}
// "c.wrap is not a function"
els.forEach((el) => el.wrap('<div class="testWrap"></div>'))
But using jQuery I can get the following to work:
works: $('.containerA').wrap('<div class="testWrap"></div>'); // wraps all elements
works: $('.containerA:first-of-type').wrap('<div class="testWrap"></div>'); // wraps specified element
But using query selector doesnt:
document.querySelector('.containerA:first-of-type').wrap('<div class="testWrap"></div>'); // fails with error "document.querySelector(...).wrap is not a function"
So my main questions are:
How can I wrap individual elements using JS with a loop?
Why does wrap() apply to all elements when wrapAll() presumably should? (my successful JQ code applies to all elements)
Why ever use wrapAll() rather than wrap()?
Presumably wrap() is only for jQuery, but presumably JQ can work with JS, so why wouldn't wrap work after selecting an element using query selector, document get element by class name or any other JS selector?
Any explanation would be much appreciated. Is there something obvious I'm not getting? Thanks for any advice here.
document.querySelector('.containerA:first-of-type') is a valina js HTML object not a jquery's. you have to convert it into jquery object then only you can access jquery's functions.
var container = $(document.querySelector('.containerA:first-of-type'));
container.wrap('<div class="testWrap"></div>');
http://api.jquery.com/wrap/
http://api.jquery.com/wrapall/
Wrap goes around each matching element individually and WrapAll goes around all elements once.
Jquery selector must be used to apply Jquery functions, as the error says, the functions don't exist on the raw elements.
Related
Here is a part of my html. (it is written using ejs)
<div class="objAddDiv">
<tr><td><button class="addObj">Do this action</button></td></tr>
<table><div class="objects"></div></table>
</div>
I have several objAddDiv divs on this page. Each has the same structure inside of it. I use .append() to add more ejs to .objects. I am having a hard time adding to only the .objects div that is inside of the same div as the button. I tried doing the following
".addObj click": function(el, element){
$(".addObj").closest(".objAddDiv").find(".objects").append(//my ejs utility here)
}
The problem is that $(".addObj").closest(".objAddDiv") returns all .objAddDiv on the page. I have looked at the jquery documentation for .closest and it says closest should only return one element. Is there a better way to do this? What am I doing wrong. (these are not my real class names btw)
It's because you are calling that method on every element with a class of 'addObj':
For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
So you get the closest objAddDiv to each addObj element.
Assuming you are doing this inside the click event of the button use this to get the correct element:
$(this).closest(".objAddDiv").find(".objects").append(//my ejs utility here)
Here is the answer that I figured out (for anyone who comes next) I needed to use the element I passed into the function:
el.closest(".objAddDiv").find(".objects").append(//ejs append stuff)
Due to a table plugin I am using, I have to resort to using jQuery to add a div around a table after the fact. I am trying to use before/after functions but it doesn't appear to be working.
Code here: http://jsfiddle.net/LWXQK/1/
Jquery code:
$('#dashboard').before("<div class='reclass'>");
$('#dashboard').after("</div>");
Expected result:
<div class='reclass'><table id='dashboard'></table></div>
Actual result:
<div class='reclass'></div><table id='dashboard'></table>
Does anyone know what the problem might be or an alternative?
That's not how DOM functions, you should add an element to the DOM, jQuery calls createElement() method of the document object behind the scene, since the first parameter passed to .before() is valid .before() inserts an element before the table, however the second parameter is not and .after() doesn't do anything, otherwise it would insert another element after the table, you can use .wrap() method:
$('#dashboard').wrap("<div class='reclass'></div>");
I'm using AJAX to fetch some HTML markup. I want to append some style tags (with a class) from the fetched markup to my own document using find(). However, jQuery does not seem to like the following approach.
(link removed due to lack of reputation)
Could someone shed some light on why this does not work, and point me in the right direction?
Thank you in advance.
Solutions
Making it a native element first (and removing script tags as extra precaution) works. http://jsfiddle.net/T6QCR/5/
Also, a lot simpler, using innerHTML instead of .html() works, as setting innerHTML does not evaluate scripts and allows .find() to function. http://jsfiddle.net/T6QCR/8/
Also, laconbass' answer below.
Thank you for the help!
Parse the HTML chunk rather than just passing it to jQuery
From the jQuery function documentation for the case you are using:
(...) if the string appears to be an HTML snippet, jQuery attempts to
create new DOM elements as described by the HTML. Then a jQuery object
is created and returned that refers to these elements. You can perform
any of the usual jQuery methods on this object.
(...)
If the HTML is more complex than a single tag without attributes, as
it is in the above example, the actual creation of the elements is
handled by the browser's innerHTML mechanism. In most cases, jQuery
creates a new element and sets the innerHTML property of the
element to the HTML snippet that was passed in.
(...)
When passing in complex HTML, some browsers may not generate a DOM
that exactly replicates the HTML source provided. As mentioned, jQuery
uses the browser"s .innerHTML property to parse the passed HTML and
insert it into the current document. During this process, some
browsers filter out certain elements such as , , or
elements. As a result, the elements inserted may not be
representative of the original string passed.
The documentation recomends ussing $.parseHtml()
For explicit parsing of a string to HTML, use the $.parseHTML()
method.
$.filter rather than $.find
As you noted, $.find does not work on this example. I had succeed replacing it with a $.filter call.
// this works
$html.filter('.test');
// this doesn't works
$html.find('.test');
// better if you filter also by tag
// surely you will have more tags other than <style> on the retrieved html
$html.filter('style.test');
See how this applies to your example on this fiddle.
body is not defined, the console gives an indication of this by way of an error, too. If you want to use jQuery to select the markup body and append the style then you will need to use an appropriate selector:
$("body").append($style);
<style> element can't has class attribute, because Uncaught SyntaxError: Unexpected identifier.
This code shoud work:
var html = '<html><head><style>aaa</style></head></html>';
var $html = $.parseHTML(html);
$.each($html, function(i, el) {
if(el.nodeName == "STYLE") {
$("head").append(el.outerHTML);
return false;
}
});
I'm not really sure as to why this is, but it has something to do with the document model and how it works. You can't just hold a temporary var with the html text in it, you need to put it all inside an element (like a div) that is attached to the document in some way. This div could be hidden from view from the user.
<html>
<head>
<div></div>
</head>
<body>
<script>
jQuery(document).ready(function($) {
$('div').hide().html('<html><head><style class="test"></style></head></html>'); // From AJAX request
var $style = $('div').find('.test');
document.body.appendChild($style[0]);
});
</script>
</body>
</html>
I'm new to Protoype.JS and just testing it a bit because I heard it was good, but I'm stuck quite quickly.
As easy as this is with jQuery, it seems to be the end of the world to get the text in an element. I've tried innerHTML in multiple ways but the only thing I can get is "undefined".
alert($$('.mnu_item').innerHTML);
alert($('content').innerHTML);
None of these work.
Content is a div with id "content" and .mnu_item is an anchor tag with class ".mnu_item".
I don't get what the problem is, probably something stupid but it would be great if somebody could point me in the right direction!
EDIT: I've found that it isn't the innerHTML that doesn't work but it's the class selector. The second line in the code above does work. How can I select an element by its class in the latest Prototype version if this isn't the correct way?
Has the DOM loaded when you run your script? If you're not running this code in a window.onload or by placing it at the end of the body, then the elements by not exist when it runs.
Try placing your script just inside the closing </body> tag.
<body>
<!-- my content -->
<script type="text/javascript">
alert($('content').innerHTML);
</script>
</body>
Also, your first line is selecting correctly, but will return an Array of elements, so innerHTML will be undefined.
To iterate the Array, you can do this:
$$('.mnu_item').each(function(val,i) {
alert(val.innerHTML);
});
or if you want to end up with an Array of the innerHTML values, do this:
var values = $$('.mnu_item').map(function(val,i) {
return val.innerHTML;
});
Make sure the DOM is loaded before you run these tests:
$(document).on('dom:loaded', function () {
/* code to execute after dom has loaded */
})
The first line of code $$('.mne_item') doesn't work because $$ gives back an array of all elements matching the css rule. So $$('.mne_item') gives an array of all dom elements which has the class mne_item. You can ask the first one by using the first method or iterate over all items like this:
$$('.mne_item').each(function(elem) {
// elem is the li elements extended by all Element methods of prototype
});
If you use $ in jQuery, it actually uses a similar pattern but hides the each construct. It just applies the chained method to all elements or just the first.
The second line of code $('content').innerHTML should work. $ is a shortcut for document.getElementById so it should give you a DOM node back. The reason why this doesn't work is there is no node where id = content, probably because the dom isn't loaded yet.
For more info about the methods of prototype look at the api: http://api.prototypejs.org/
Also check the default DOM methods: http://quirksmode.org/dom/w3c_core.html
$('content').innerHTML should work. Check your HTML, ensure the ID is unique.
var text = $$('label[for="display_on_amazon"]').first().textContent;
Above code worked for me.
Regarding, $$('.mnu_item').innerHTML
When you are trying to fetch with class selector, prototype returns array of multiple elments, by using [0] or first() method system will point at the first element in that array, after that you can use innerHtml (to get html inside the element) or textContent (to get text content of that element, native javascript method)
This might be a very simple thing in jquery but I am not able to figure it out. My html document has the following structure
<div class="body">
<p>This is the text I want to extract</p>
</div>
I tried this
$("body").find("a p").text()
but this does not seem to be working for me. I am able to get the paragraph object but not the text. I tested it with console.log with no use.
What you have should be working (you can test it here), make sure you're running it when the DOM is ready though, like this:
$(function() {
alert($("body").find("a p").text()); //or just $("a p").text()
});
If it runs earlier, the elements may not be ready, and your selector won't find any matches.
If you want to select the class body make sure to use ".body" instead of "body" (which would select the <body> element). Here's a version using the .class selector:
$(function() {
alert($(".body a p").text());
});
the .html() function retrieves a nodes inner html.
$('.body a p').html();
should do the trick
Not sure if this would cause a problem, but you have invalid markup. From "The global structure of an HTML document" by the W3C
Generally, block-level elements may contain inline elements and other block-level elements. Generally, inline elements may contain only data and other inline elements. Inherent in this structural distinction is the idea that block elements create "larger" structures than inline elements.
a elements are supposed to be contained by block elements like p, not the other way around.
here is your paragraph element in html or php file which is id assign tt
<p id="tt">ALert Message </p>
in in jquery file to get the text of your paragraph with tt id can be
var tt = $("#tt").text();
alert(tt);
working fine for jquery-3.1.1.js