How to set dom's text in pure javascript?
I want to set ul object's text value.
So i tried below.
getElementByID("DropDown").textContent = "text";
But the ul's child is disappeared when i set the textcontent.
It has same result in innerHtml and innerText.
getElementByID("DropDown").innerText= "text";
getElementByID("DropDown").innerHtml= "text";
Then i must appendChild(TextNode) to ul? I think it is too complex.
I must append TextNode and i must save the TextNode's ref.
Is there have any easy way?
innerHTML is just a string. If you overwrite it, it loses its previous content. But, you can append to it instead, and then it does not lose its previous content. See magic1
And magic2 shows the createElement+appendChild way. While it has more lines, it is easier to manage if you want to set various attributes of an element (style, event handlers and others - not necessarily for this particular case of list items, but in general).
var i=0;
function magic1(){
i++;
document.getElementById("myUL").innerHTML+="<li>Testx"+i+"</li>";
}
function magic2(){
i++;
var li=document.createElement("li");
li.innerHTML="Testy"+i;
document.getElementById("myUL").appendChild(li);
}
<button onclick="magic1()">ClickMe1</button>
<button onclick="magic2()">ClickMe2</button>
<ul id="myUL"></ul>
Related
I am trying to add some text to an existing element using textContent. But when I use +=(addition assignment) operator but in the result, already existing tags like b has lost its effect. I think I am just adding to it, but it also has effect in the previous content. Can anyone explain why? I checked the docs but didn't find anything about this.
HTML:
<div id="divA">Something<b>bold</b></div>
JS
const some = document.getElementById("divA");
some.textContent += "Hi"; // This results in : "Something boldHi" without the bolded formatting.
some.textContent = some.textContent + "Hi"; //This too results in the same!
Thanks in advance!
The .textContent value of an element returns just that - the text content, which is plain text, not the HTML markup of the contents.
If you do
some.textContent += "Hi"
The text content of the container will be retrieved, which will not contain any tags - eg
<div id="divA">Something<b>bold</b></div>
will retrieve:
Something bold
Concatenating onto that and then assigning the result back to the .textContent of the element results in the element's descendants replaced with a single text node, where the text node's value is the value assigned.
If you use .innerHTML += instead, the prior HTML markup of the descendants will be preserved - but the descendants will all be re-parsed according to the HTML markup assigned, so event listeners and related things that depend on DOM elements will be lost. A better option is to use .insertAdjacentHTML, which does not require re-parsing of the descendants.
An even better option would be to append a node itself instead of trying to write HTML markup (which is potentially unsafe), eg
some.appendChild(document.createTextNode('Hi'))
When you are taking the textContent then you will get Somethingbold which is just plain text wihtout HTML tags
console.log(some.textContent); // Somethingbold
You are appending the textContent, instead you shold use innerHTML
const some = document.getElementById("divA");
some.innerHTML += "Hi"; // This results in : "Something boldHi" without the bolded formatting.
some.innerHTML = some.innerHTML + "Hi"; //This too results in the same!
<div id="divA">Something<b>bold</b></div>
What's the advantage of creating a TextNode and appending it to an HTML element over setting directly its textContent?
Let's say I have a span.
var span = document.getElementById('my-span');
And I want to change its text. What's the advantage of using :
var my_text = document.createTextNode('Hello!');
span.appendChild(my_text);
over
span.textContent = 'hello';
It 's not really matter of advantage but of proper usage depending on the need.
The fundamental difference is that:
createTextNode() is a method and works just as its name says: it creates an element... then you must do something with it (like in your example, where you append it as a child);
so it is useful if you want to have a new element and place it somewhere
textContent is a property you may get or set, with a unique statement and nothing else;
so it is useful when you only want to change the content of an already existing element
Now in the precise case of your question, you said you want to change the text of the element...
To be more clear say you have the following HTML element:
<span>Original text</span>
If you're using your first solution:
var my_text = document.createTextNode('Hello!');
span.appendChild(my_text);
then it will end with:
<span>Original textHello!</span>
because you appended your textNode.
So you should use the second solution.
I am writing a small library where I am in need of selecting a relative element to the targeted element through querySelector method.
For example:
HTML
<div class="target"></div>
<div class="relative"></div>
<!-- querySelector will select only this .target element -->
<div class="target"></div>
<div class="relative"></div>
<div class="target"></div>
<div class="relative"></div>
JavaScript
var target = document.querySelectorAll('.target')[1];
// Something like this which doesn't work actually
var relativeElement = target.querySelector('this + .relative');
In the above example, I am trying to select the .relative class element relative only to the .target element whose value is stored in target variable. No styles should apply to the other .relative class elements.
PS: the selectors can vary. So, I can't use JavaScript's predefined methods like previousElementSibling or nextElementSibling.
I don't need solution in jQuery or other JavaScript libraries.
Well it should be ideally:
var relativeElement = target.querySelector('.relative');
But this will actually try to select something inside the target element.
therefore this would only work if your html structure is something like:
<div class="target">
<div class="relative"></div>
</div>
Your best bet would probably in this case be to use nextElementSibling which I understand is difficult for you to use.
You cannot.
If you insist on using the querySelector of the subject element, the answers is there is no way.
The spec and MDN both says clearly that Element.querySelector must return "a descendant of the element on which it is invoked", and the object element you want does not meet this limitation.
You must go up and use other elements, e.g. document.querySelector, if you want to break out.
You can always override Element.prototype.querySelector to do your biddings, including implementing your own CSS engine that select whatever element you want in whatever syntax you want.
I didn't mention this because you will be breaking the assumption of a very important function, easily breaking other libraries and even normal code, or at best slowing them down.
target.querySelector('.relative');
By using querySelector on the target instead of document, you scope the DOM traversal to the target element.
It is not entirely clear from your explanation, but by related i assume you mean descendant?
To get all target elements you can use
document.querySelectorAll('.target')
And then iterate the result
I found a way which will work for my library.
I will replace "this " in the querySelector with a unique custom attribute value. Something like this:
Element.prototype.customQuerySelector = function(selector){
// Adding a custom attribute to refer for selector
this.setAttribute('data-unique-id', '1');
// Replace "this " string with custom attribute's value
// You can also add a unique class name instead of adding custom attribute
selector = selector.replace("this ", '[data-unique-id="1"] ');
// Get the relative element
var relativeElement = document.querySelector(selector);
// After getting the relative element, the added custom attribute is useless
// So, remove it
this.removeAttribute('data-unique-id');
// return the fetched element
return relativeElement;
}
var element = document.querySelectorAll('.target')[1];
var targetElement = element.customQuerySelector('this + .relative');
// Now, do anything with the fetched relative element
targetElement.style.color = "red";
Working Fiddle
I need to replace each word in the textarea by a span with unique id. I need the code in JavaScript. I have tried creating a DOM element and inserting it in text area using the following code.
var s = document.createElement('span');
var text=document.createTextNode("inside tag");
s.appendChild(text);
document.getElementById("t1").appendChild(s);
t1 is the is the id of my text area. The above code isn't giving any result.
Also, I tried another method:
document.getElementById("t1").innerHTML="<span>inside tag</span>";
innerHTML isn't working here.
What do I do?
It has to be the value property instead of the innerHtml because of the fact that value property is used for setting the value for input/form elements. innerHTML on the other hand is normally used for div, span, td and similar elements.
So as you are using a textarea you shall go with value property.
document.getElementById("t1").value = "Whatever the text/html you want to insert here";
To change your value of text arena, you will have to do this:
document.getElementById('t1').value = '<span>inside tag</span>';
I have a div set up something like this:
<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>
EDIT: To clarify, this is the simplest example. The div could have any arbitrary number of n deep nested children.
$('#test').getText() returns 'Hello Goodbye'. Here's a one liner to test in Firebug: jQuery('<div id="test"> <p>Hello</p> <p style="display: none">Goodbye</p> </div>').text()
This seems to be because what jQuery uses internally, textContent (for non IE), returns hidden elements as part of the text. Hrmph.
Is there a way to return the text content ignoring display:none'd elements? Basically I am trying to mimic the text you would get from highlighting the div with your mouse and copying to system clipboard. That ignores hidden text.
Interestingly, if you create a selection range and get the text from it, that also returns text inside display:none elements.
var range = document.body.createTextRange();
range.moveToElementText($('#test')[0]);
range.select();
console.log(range.toString()); // Also logs Hello Goodbye!
So creating a document selection range doesn't appear to do the same thing as highlighting with the mouse in terms of display:none elements. How do I get around this dirty pickle conundrum?
Edit: using .filter(':visible').text has been suggested, but it won't work for this scenario. I need the returned text to be EXACTLY what would come from a selection with the mouse. So for example:
$('<div>test1 <p>test2</p>\r\n <b>test3</b> <span style="display:none">none</span></div>').appendTo(document.body).children().filter(':visible').text()
returns
"test2test3"
When the output I actually want is
test1 test2
test3
linebreaks, whitespace and all, which come from the \r\n
Filter the elements using .filter(":visible").
Or use this:
$("#test :visible").text();
But the jQuery documentation advises us to use .filter() instead:
Because :visible is a jQuery extension and not part of the CSS specification,
queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").
Use :visible in your selector as such:
$("#test > p:visible").text()
A Function example:
-- Edit:
http://jsfiddle.net/8H5ka/ ( Works on Chrome it displays "Hello" in Result )
If the above doesn't work:
http://jsfiddle.net/userdude/8H5ka/1/
If space isn't a major concern you could copy the markup, remove the hidden elements, and output that text.
var x = $('#test').clone();
x.filter(':not(:visible)').remove();
return x.text();
I had this problem and found this question, and it seems the actual solution is based on the provided answers but not actually written out. So here's a complete solution that worked for my situation, which is the same as the OP with the additional provision that elements may be invisible due to external styles based on DOM position. Example:
<style>.invisible-children span { display: none; }</style>
<div class="invisible-children">
<div id="test">Hello <span>Goodbye</span></div>
</div>
The solution is to:
Make a clone of the entire object.
Remove invisible objects in place; if we take #test out of the DOM before we remove invisible objects, jQuery might not know they're invisible because they will no longer match the CSS rules.
Get the text of the object.
Replace the original object with the clone we made.
The code:
var $test = $('#test');
// 1:
var $testclone = $test.clone();
// 2: We assume that $test is :visible and only remove children that are not.
$test.find('*').not(':visible').remove();
// 3:
var text = $test.text();
// 4:
$test.replaceWith($testclone);
// Now return the text...
return text;
// ...or if you're going to keep going and using the $test variable, make sure
// to replace it so whatever you do with it affects the object now in DOM and
// not the original from which we got the text after removing stuff.
$test = $testclone;
$test.css('background', 'grey'); // For example.
Here is how I did it with MooTools:
$extend(Selectors.Pseudo, {
invisible: function() {
if(this.getStyle('visibility') == 'hidden' || this.getStyle('display') == 'none') {
return this;
}
}
});
Element.implement({
getTextLikeTheBrowserWould = function() {
var temp = this.clone();
temp.getElements(':invisible').destroy();
return temp.get('text').replace(/ |&/g, ' ');
}
})
I search for that and found this question but without solution.
Solution for me is just get out of jquery to use DOM:
var $test = $('#test').get(0).innerText
or if more than on element in array of selector, you need a for loop and a merge but I guess that most of time it is the first version that you need.
var $test = $('#test').get().map(a => a.innerText).join(' ');