select specific elements in parent div - javascript

im trying to get an article from a div, and the problem is it gets everything when i use $('#article').html() is there a way for just getting a spesific html inside the parent div without other elements?
<div id="article">
This is an article
blabla
<br/>
<b>something bold here</b>
<div id="unknown">{some javscript}</div>
<link type="anything" url="somewhere">
<style>
.something
</style>
the end of the article
</div>
should return
this is an article
blabla
<br/>
<b>something bold here</b>
the end of the article

See http://jsfiddle.net/TULKC/
var el=document.getElementById('article'),
text=getText(el);
function getText(el){
var els=el.childNodes,
t='';
for(var i=0;i<els.length;i++){
if(els[i].nodeType==3){//If it's a text node
if(!/^\s+$/.test(els[i].nodeValue)){//We avoid spaces
t+=els[i].nodeValue;
}
}else if(els[i].nodeType==1){//If it's an element node
var nName=els[i].nodeName.toLowerCase(),
c=check(nName);
if(c==1){//Allowed elements
t+='<'+nName+'>'+getText(els[i])+'</'+nName+'>';
}else if(c==2){//Allowed self-closing elements
t+='<'+nName+' />';
}
}
}
return t;
}
function check(nodeName){
switch(nodeName){
case 'b': return 1;//Allowed elements
case 'br':return 2;//Allowed self-closing elements
default:return 0;
}
}
alert(text);
Note: You can add more exceptions this way:
switch(nodeName){
case 'b': case 'a': return 1;//Allowed elements
case 'br':case 'img':return 2;//Allowed self-closing elements
default:return 0;
}
(Well, if you use HTML5, img is not a self-closing element)
Edit:
If you want to keep the attributes, you can use the following function
function getAttr(el){
var attr=el.attributes,
t='';
for(var i=0;i<attr.length;i++){
t+=' '+attr[i].nodeName+'="'+attr[i].nodeValue+'"';
}
return t;
}
and then
if(c==1){
t+='<'+nName+getAttr(els[i])+'>'+getText(els[i])+'</'+nName+'>';
}else if(c==2){
t+='<'+nName+getAttr(els[i])+' />';
}
See it here: http://jsfiddle.net/TULKC/4/

Something like this should get you what you want I guess:
​(function($) {
$article = $('#article').clone();
$('div, link, style', $article).remove();
console.log($article.html());
})(jQuery);​
Demo: http://jsfiddle.net/EQ7zC/

You can use innerText or .text() in jQuery to get all text without tags, including the text in childs.
Also, if you need to get only the text in parent div, without the text of child elements, you can iterate it's child nodes, and check if it is text node.
Something like this:
var innerText = "";
$('#yourDiv').each(function(){
var $cn = this.childNodes;
for (var i = 0, l = $cn && $cn.length || 0; i < l; i++) {
if ($cn[i].nodeType == 3 && String($cn[i].nodeValue).split(/\s/).join('')) {
innerText += $cn[i].nodeValue;
}
}
});
console.log(innerText);

is this a possibility ?
<div id="article">
<a>This is an article -- a starts article
blabla
<br/>
<b>something bold here</b>
</a> -- /a ends article
<div id="unknown">{some javscript}</div>
<link type="anything" url="somewhere">
<style>
.something
</style>
the end of the article
$('#article').find('a').html();

Related

I need to select multiple SPAN elements

On my web page I want to 'hide' or 'unhide' several elements (C and F in this example) that are already inside a DIV element,
such as:
<div> Select A or B <span name='hide' > or C</span></div>
<div> Also select D or E <span name='hide' > or F</span></div>
(etc)
I use javascript to hide all 'hide' elements when the page is opened, except when the page is opened on localhost, than all is shown.
I do not necessarily know how many 'hide' elements there are (dynamically generated).
var hids=document.getElementsByName('hide');
if(hids!=null) {
for(var j=0; j< hids.length; j++) {
if(localhost==true) { // only if on localhost
hids[j].style.visibility='visible';
}
else hids[j].style.visibility='hidden';
}
}
But, the 'name' attribute is not valid for SPAN. When I use DIV instead of SPAN it messes up the format. How should I solve this properly?
Use class instead of name:
<span class="my-class"> or C</span>
and getElementsByClassName instead of getElementsByName:
document.getElementsByClassName("my-class");
If span doesn't have a name attribute, try with class name
var hids=document.getElementsByClassName('hide');
And change your html to
<div> Select A or B <span class='hide' > or C</span></div>
<div> Also select D or E <span class='hide' > or F</span></div>
You can use querySelectorAll to find by className hide
var localhost = false;
var hids = document.querySelectorAll('.hide');
if (hids != null) {
for (var j = 0; j < hids.length; j++) {
if (localhost) { // only if on localhost
hids[j].style.visibility = 'visible';
} else hids[j].style.visibility = 'hidden';
}
}
<div> Select A or B <span class='hide'> or C</span></div>
<div> Also select D or E <span class='hide'> or F</span></div>
(etc)
Resource
document.querySelectorAll()
Use data-XXX attribute instead of name, e.g.: <span data-name='hide'>
For sure, in this case, you will need to fetch them like this:
document.getElementsByTagName("data-name") and do another filtering based on the value of the data-name tag.
Im not sure the name property should be used here. I believe names are intended to be unique. So instead maybe through class name;
let localhost = true;
let hideList = document.getElementsByClassName("hide");
if (hideList != null) {
for (var j=0; j < hideList.length; j++ ) {
if (localhost === true) {
hideList[j].style.visibility = 'visible'
} else {
hideList[j].style.visibility = 'hidden'
}
}
}
As for the <div> messing up your formatting; thats likely due to a style property: display. <span>'s behave like display: inline; while <div>'s behave like display: block;. You can override this default behavior in your own CSS. Go ahead and turn those <spans>'s into <div>'s and apply some CSS:
<div> Select A or B <div class="hide"> or C</div></div>
<div> Also select D or E <div class="hide"> or F</div></div>
<style>
.hide {
display: inline;
}
</style>
The result should be visually identical to when using spans.

Select elements outside another specific element

I am trying to select one ore more elements that are NOT descendants of another specific element.
<html>
<body>
<div>
<p>
<b>
<i> don't select me </i>
</b>
</p>
</div>
<div>
<i>don't select me either </i>
</div>
<i> select me </i>
<b>
<i> select me too </i>
</b>
</body>
</html>
In the example above I want to select all 'i' elements, that are not inside div elements.
The other way around would be easy, with ('div i'), but using this in :not() is not possible.
How can I select all i elements outside of div elements?
Often it is suggested the use of jQuery, which would be like:
nondiv_i = all_i.not(all_div.find("i"))
I can't use jQuery, but could use jqLite - jqLite does not have a not()-function. A jqLite solution is welcome too!
Is it possible to do this without repeated iterations and comparisons?
Edit: To clarify, i don't want to have any div-ancestors for my i-elements, not only no direct div-parents.
A comparable XPath would look like this:
//i[not(ancestor::div)]
function isDescendant(parent, child) {
var all = parent.getElementsByTagName(child.tagName);
for (var i = -1, l = all.length; ++i < l;) {
if(all[i]==child){
return true;
}
}
return false;
}
for the specific case of yours;
is = document.getElementsByTagName("i");
divs = document.getElementsByTagName("div");
nondivs = [];
var contains;
for(i=0;i<is.length;i++){
contains = false;
for(j=0;j<divs.length;j++){
if(isDescendant(divs[j],is[i])){
contains = true;
j = divs.length;
}
}
if(!contains){
nondivs.push(is[i]);
}
}
Add a class to all of the <i> tags ("itag", for example). From there, you can fetch them by calling getElementsByClassName:
var r = document.getElementsByClassName("itag");
console.log("length" + r.length);
You can then get them by index:
console.log(r[0]);
console.log(r[1].innerHTML); // get text of i tag

Changing properties of all <hr> html elements

In css I have set all the <hr> elements in my html to "display:none;" which works.
I have an onclick event listener set up to change the "display" to "block".
I use:
document.getElementsByTagName("hr").innerHTML.style.display = "block";
I get an error "Cannot read property 'style' of undefined".
Do it the following way:
var hrItems = document.getElementsByTagName("hr");
for(var i = 0; i < hrItems.length; i++) {
hrItems[i].style.display = 'block';
}
This is incorrect in two ways
getElementsByTagName gives you a list on elements and there is no method to operate on all elements, so you'll have to loop through all of them and add the required style individually.
innerHTML returns a string containing the mark up in an element but <hr> doesn't have any thing in it and the style property is on the <hr> itself.
var hrs = document.getElementsByTagName("hr");
for(var i = 0; i < hrs.length; i++) {
hrs[i].style.display = 'block';
}
Simple (and very effective) solution:
tag your body with a class-element
<body class="no_hr"> <article><hr/> TEXT Foo</article> <hr/> </body>
in css don't hide hr directly, but do
.no_hr hr {
display:none;
}
now define a second style in your css
.block_hr hr{
display:block;
}
in your buttons onClick, change the one and only body class from no_hr to block_hr
onclick() {
if ( document.body.className == "no_hr" ) {
document.body.className = "block_hr";
} else {
document.body.className = "no_hr";
}
}
This is a very charming solution, because you don't have to iterate over elements yourself, but let your browsers optimized procedures do their job.
For people who want a solution that doesn't require JavaScript.
Create an invisible checkbox at the top of the document and make sure that people can click on it.
<input type="checkbox" id="ruler"/>
<label for="ruler">Click to show or hide the rules</label>
Then tell the stylesheet that the <hr>s should be hidden by default, but should be visible if the checkbox is checked.
#ruler, hr {display:none}
#ruler:checked ~ hr {display:block}
Done. See fiddle.
getElementsByTagName() returns a node list, and therefore you must iterate through all the results. Additionally, there is no innerHTML property of an <hr> tag, and the style must be set directly on the tag.
I like writing these types of iterations using Array.forEach() and call:
[].forEach.call(document.getElementsByTagName("hr"), function(item) {
item.style.display = "block";
});
Or, make it even easier on yourself and use jQuery:
$("hr").show();

remove text from multiple spans having same id [duplicate]

This question already has answers here:
javascript variable corresponds to DOM element with the same ID [duplicate]
(3 answers)
Closed 9 years ago.
I have multiple spans
<span id ="myId">data1</span>
<span id ="myId">data2</span>
<span id ="myId">data3</span>
<span id ="myId">data4</span>
<span id ="myId">data5</span>
I want to delete text inside all span on single button click.
I tried this on button click in javascript
document.getElementById("myId").innerHTML = "";
but it is removing text from only 1st span
IDs are unique, Classes are repeatable
The purpose of an id in HTML is to identify a unique element on the page. If you want to apply similar styles or use similar scripts on multiple elements, use a class instead:
<span class="myClass">data1</span>
<span class="myClass">data2</span>
<span class="myClass">data3</span>
<span class="myClass">data4</span>
<span class="myClass">data5</span>
<input type="button" id="clearbutton" value="Clear Data">
Now let's remove the text
Now, you can select all of these elements and set their text to anything you want. This example uses jQuery, which I recommend because older versions of IE don't support getElementsByClassName:
$('#clearbutton').click(function() {
$('.myClass').text('');
});
Link to Working Demo | Link to jQuery
Or in Vanilla JS
If you're not worried about supporting IE, you can do this with vanilla JavaScript:
function clearSpans() {
var spans = document.getElementsByClassName("myClass");
for(var i=0; i < spans.length; i++) ele[i].innerHTML='';
}
Link to Working Demo
Note: You can add getElementsByClassName to IE
I wouldn't recommend doing this because it's simpler and more widely accepted to just use jQuery, but there have been attempts to support older IEs for this function:
onload=function(){
if (document.getElementsByClassName == undefined) {
document.getElementsByClassName = function(className)
{
var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
var allElements = document.getElementsByTagName("*");
var results = [];
var element;
for (var i = 0; (element = allElements[i]) != null; i++) {
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
results.push(element);
}
return results;
}
}
}
Link to source
Dont give same ID to more than one one tag, use class instead
<span class ="myId">data1</span>
<span class ="myId">data2</span>
<span class ="myId">data3</span>
<span class ="myId">data4</span>
<span class ="myId">data5</span>
call this function to clear
function clearAll()
{
var ele= document.getElementsByClassName("myId");
for(var i=0;i<ele.length;i++)
{
ele[i].innerHTML='';
}
}
You are using a DOM method that relies to the DOM of ID, that is, per DOM, there can only be one element with the same ID.
However, you do not use the id attribute that way in your HTML, so instead you are looking for the selector to query all elements with the id myId, you perhaps know it from CSS:
document.querySelectorAll("#myId").innerHTML = '';
This does not work out of the box, you also need to add the innerHTML setter to the NodeList prototype, but that is easy:
Object.defineProperty(NodeList.prototype, "innerHTML", {
set: function (html) {
for (var i = 0; i < this.length; ++i) {
this[i].innerHTML = html;
}
}
});
You find the online demo here: http://jsfiddle.net/Pj4HD/
var spans=document.getElementsByTagName("span");
for(var i=0;i<spans.length;i++){
if(spans[i].id=="myId"){
spans[i].innerHTML="";
}
}
Although I suggest you don't keep same IDs
http://jsfiddle.net/YysRp/

getElementById with changing IDs

I need to hide all the elements that have the string "replies-36965584" anywhere in their IDs.
HTML:
<div id="replies-36965584_1">aaaa</div>
<div id="replies-36965584_2">aaaa</div>
<div id="replies-36965584_3">aaaa</div>
<div id="replies-36965584_4">aaaa</div>
<div id="replies-36222224_2">nnnn</div>
JavaScript:
document.getElementById("replies-36965584").style.display="none"
How can I modify this JS to select the first four elements?
You can do this with CSS and attribute selectors.
[att^=val]
Represents an element with the att attribute whose value begins with the prefix "val". If "val" is the empty string then the selector does not represent anything.
Source: http://www.w3.org/TR/css3-selectors/#attribute-substrings
jsfiddle
CSS
[id^="replies-36965584_"] {
display: none;
}
Is using jQuery an option? If so, this is dead simple:
$(document).ready(function(){
$('div[id^="replies-36965584"]').hide();
});
If you're unfamiliar with jQuery, here's a link to get started: http://learn.jquery.com/javascript-101/getting-started/
EDIT: Fixed syntax error.
EDIT: Added jsFiddle: http://jsfiddle.net/xbVp9/
If you don't know certain literal values but you know the general pattern and only the number will change, then I will consider some matching with regular expresiion.
You can do it the painful way:
var o = document.getElementsByTagName("div");
for (var i=0;i<o.length;i++) {
if(o[i].id.indexOf('replies-36965584') == 0) {
o[i].style.display = 'none';
}
}
The only way to do this with vanilla javascript that I know of, is to fetch all the divs on the page, and test the id's for the ones you want.
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; ++i) {
var div = divs[i];
if (/replies-36965584/.test(div.id)) {
div.style.display = 'none';
}
}

Categories