I have this html
<div id="editor" contenteditable="true">
This text is directly under div
<p>Some text under p tag. <span> Some under span tag</span> and this is another text</p>
<p>Another para</p>
</div>
<button>Get block level parent</button>
Javascript
function getParentBlock() {
element = document.getSelection().focusNode;
while (p = element.parentNode) {
displaystyle = window.getComputedStyle(p, null).getPropertyValue('display');
if (displaystyle == 'block') {
return p;
}
element = element.parentNode;
}
}
function alertCurrentParent() {
alert(getParentBlock());
}
btn = document.querySelector('button');
btn.onclick = alertCurrentParent;
The jsfiddle is here: http://jsfiddle.net/shankardevy/aA8Kb/
Now when I place the cursor inside the text 'Another Para' or doubleclick the 'Another Para' (which in my mac selects the whole para) and click the button 'Get block level parent', I get HTMLParagraphElement in alert.
However, when I place the cursor in first para ("Some text under p tag"), and I click the button, I get "HTMLParagraphElement" in alert. And when I double click the second para which selects the entire first paragraph, and click the button, I get "HTMLDivElement".
I want my code to work as in the second paragraph. i.e., double click the sentence and click the button, it should show me "HTMLParagraphElement". How do I do that?
Any help is much appreciated!
The problem is that you start your loop with the parent node. When you select the entire paragraph, its parent is the DIV. So start your loop at the current element instead of the parent.
function getParentBlock() {
var element = document.getSelection().focusNode;
for (var p = element; p; p = p.parentNode) {
var style = window.getComputedStyle(p, null);
if (style) {
var displaystyle = style.getPropertyValue('display');
if (displaystyle == 'block') {
return p;
}
}
}
}
FIDDLE
You have to test the result of getComputedStyle before calling getPropertyValue, because text nodes don't have a style and it returns null.
Related
On my index.JS file, I created elements using documentCreateElement and appended them to the DOM to show data from an api. Then I created an event listener which works where if I click my H3 element, it will show my H4 and P element. But I want it to where if I click my H3 element again, I want the H4 and P elements to hide. This is the code I have for my click event listener:
`H3.addEventListener(‘click’, clickFunction)
Function clickFunction() {
Div.append(h4)
Div.append(p)
}`
Can someone please help me?
I tried to look up toggling functions online or incorporate CSS hidden class to the h4 and p elements but nothing was hiding
Try modifying your clickFunction() to check if the elements are already displayed or not.
let isDisplayed = false;
function clickFunction() {
if (isDisplayed) {
// If the elements are already displayed, hide them
h4.style.display = "none";
p.style.display = "none";
isDisplayed = false;
} else {
// If the elements are not displayed, show them
div.appendChild(h4);
div.appendChild(p);
isDisplayed = true;
}
}
h3.addEventListener("click", clickFunction);
In above example, its a boolean variable isDisplayed to keep track of whether the elements are currently displayed or not. When the h3 element is clicked, the clickFunction() is called, and it checks the value of isDisplayed. If its true, it means the elements are already displayed, so we hide them by setting their display style to "none" and setting isDisplayed to false. If it's false, it means the elements are not displayed, so we show them by appending them to the div and setting isDisplayed to true.
Note that you'll need to deeclare the isDisplayed variable outside of the clickFunction() so that its value is preserved between function calls. And make sure to select the h4, p, and div elements using document.querySelector() or a smilar method before using them in the function.
You can try this in your clickFunction
Function clickFunction() {
if(!Div.hasChildNodes()) {
Div.append(h4)
Div.append(p)
} else {
Div.removeChild(Div.childNodes(0))
Div.removeChild(Div.childNodes(1))
}
}
Check this for more info.
Follow the below steps-
Find the existing p and h4 elements.
If found then remove those using the removeChild method, else append those using the append method.
Here is a working demo of toggling the elements-
let h3 = document.querySelector('h3');
h3.addEventListener('click', clickFunction)
let div = document.querySelector('div');
function clickFunction() {
// Find already exists p and h4 elements
let p_exists = document.querySelector('p');
let h4_exists = document.querySelector('h4');
// If found then remove one by one
if (p_exists && h4_exists) {
div.removeChild(h4_exists);
div.removeChild(p_exists);
}
// Else, create and append
else {
let h4 = document.createElement('h4')
h4.innerText = "I am a h4 element";
let p = document.createElement('p')
p.innerText = "I am a p element";
div.append(h4, p);
}
}
<h3>Click</h3>
<div></div>
Using a CSS style rule and checking for the existence of the CSS style rule class name on each HTML element's class list is a common method for toggling the display state of an element.
I used a hide class name in the code snippet but you can change to a 'show' class name with some minor modifications to the code and CSS rules.
var H3 = document.getElementById("h3-elem");
H3.addEventListener("click", clickFunction);
var Div = document.getElementById("div-elem");
function clickFunction() {
var h4 = document.getElementById("h4-elem");
var p = document.getElementById("p-elem");
if (!h4) {
h4 = appendH4();
}
if (!p) {
p = appendP();
}
// Option 1:
// Use the built-in 'toggle()' method on the class list
// for each element.
// https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle
// h4.classList.toggle("hide");
// p.classList.toggle("hide");
// Option 2:
// Check if the class list for the 'h4' and 'p' elements
// contain 'hide' class name. If the class list does not
// contain the class name then add the 'hide' class name
// to the class list.
if (h4.classList.contains("hide")) {
h4.classList.remove("hide");
} else {
h4.classList.add("hide");
}
if (p.classList.contains("hide")) {
p.classList.remove("hide");
} else {
p.classList.add("hide");
}
}
// Set to hide initially. After creation of the element,
// the 'clickFunction' will determine the display state
// of the element by checking for the existense of the
// 'hide' class name.
function appendH4() {
var h4 = document.createElement("h4");
h4.id = "h4-elem";
h4.className = "hide";
h4.textContent = "Header 4";
Div.append(h4);
return h4;
}
function appendP() {
var p = document.createElement("p");
p.id = "p-elem";
p.className = "hide";
p.textContent = "A paragraph";
Div.append(p);
return p;
}
.hide {
display: none;
}
<h3 id="h3-elem">Header 3</h3>
<div id="div-elem"></div>
I am trying to change the innerhtml of a p tag by clicking on a word, but I do not want to change the innerhtml of the word that I clicked on. I want to change the word that is displayed next to the word that I clicked on.
my html looks like this. each id of the word clicked on is followed by a black p tag with an id that is one more than the one that was clicked on
<p id="word0" data-index=0 class="russian"> люблю</p>
<p id="word1" data-index=1 class="english"></p>
the black p tag for the english word should be filled in by the english word when i click on the russian word.
here is my javascript. for the time being the words one two three ect, will be placed next to the russian word when it is clicked. is there a way that i can target the innerHTML of the tag next to the word that is clicked on?
<script>
let allWordsList = {'word0':'one','word1':'one','word2':'two','word3':'three'}
function changeText(e){
var number = e.target.id;
// Set the text to the data-index value of the HTML element:
e.target.innerHTML = allWordsList[number];
}
</script>
You are changing the innerHTML of the clicked element. e is the event for the para on which you clicked and e.target is the HTML element on which you clicked. So if you change the innerHTML of e.target then it would change its own not its next sibling.
e.target.innerHTML = allWordsList[number];
one way to solve this is:
let allWordsList = {
'word0': 'one',
'word1': 'one',
'word2': 'two',
'word3': 'three'
}
function changeText(e) {
var number = e.target.id;
var convertedNumber = allWordsList[ number ];
//Set the text to the data-index value of the HTML element:
const nextSibling = e.target.nextElementSibling;
nextSibling.innerHTML = convertedNumber;
}
const paragraphs = document.querySelectorAll(".para");
paragraphs.forEach( e => {
e.addEventListener("click", changeText);
})
<p id="word0" data-index=0 class="russian para"> люблю</p>
<p id="word1" data-index=1 class="english"></p>
<p id="word2" data-index=0 class="russian para"> люблю</p>
<p id="word3" data-index=1 class="english"></p>
I am really struggling with this.
I have two div on a page. The first one has got contents (mainly text). On the second div, I want to display the content of first div based on the position. for example if i select line 30, then the content of that line will be displayed in second div. Is there any idea to do that?
Thank you
This answer assumes you only want to copy the selected text to the new div and provices a basic idea how you can do so
In order to achieve that kind of behaviour you need to listen to the mouseup event in your container where you want text to be selected. That way we assume, that the user was selecting something and ended the selection.
I have prepared this JS fiddle for you: https://jsfiddle.net/djzkcw0m/
Code for the prove of concept:
HTML
Highlight some text with mouse in this container:
<div id="test">
This is some text and you can highlight it with your mouse
</div>
Result div:
<div id="result"></div>
JS
const testDiv = document.getElementById('test');
const resultDiv = document.getElementById('result');
function getSelectionText() {
var text = "";
if (window.getSelection) {
text = window.getSelection().toString();
} else if (document.selection && document.selection.type != "Control") {
text = document.selection.createRange().text;
}
return text;
}
testDiv.addEventListener('mouseup', function(e) {
const selectedText = getSelectionText();
resultDiv.textContent = selectedText;
})
note
Method "getSelectionText()" is found from a related question Get the Highlighted/Selected text
In my Div (Code Below) there is an onClick function that triggers the visibility of a second div, and there is also a content edible in the div as well. When I click to change the text it also triggers the visibility of the second div. How would I change the code so that I can click the text without changing the second div's visibility?
<div class="div1" id ="div1" onclick="onStepClicked()" style ="text-align:center"><p contenteditable="true" >Step 1</p></div>
Function:
function onStepClicked() {
var elem = document.getElementById('div2');
if (Visible === true) {
elem.style.display = 'none';
Visible = false;
}
else {
if (Visible === false) {
elem.style.display = 'block';
Visible = true;
}
}
}
You may trigger the click on the Parent div only and exclude the click on child in jQuery like this:
$("#div1").click(function(){
$("#div2").css('visibility','hidden');
}).children().click(function(e) {
return false;
});
If you are not OK with jQuery and are after a JavaScript - only solution, please leave a comment and let me know.
UPDATE
If you are after a JavaScript solution, here U R:
HTML
<div id ="div1" onclick="onStepClicked()" >
<p id="editable" contenteditable="true">Step 1</p>
</div>
JS
function onStepClicked(){
document.getElementById('div1').onclick = function(e) {
if(e.target != document.getElementById('editable')) {
document.getElementById('div2').style.visibility = 'hidden';
}
}
}
Try using the element>element selector in your script. It will only affect the first child element and then stop from affecting sub-child elements.
Tutorial:
(http://www.w3schools.com/cssref/sel_element_gt.asp)
I want to change content of div "act" using nextSibling of another div.
But result is - undefined.
function inner(){
var abc = document.getElementById("start").nextSibling;
document.getElementById("act").innerHTML = abc.innerHTML;
}
<img id="btnRight" src="img/btnRight.png" onclick="inner()">
<div id="act"><img src="img/home01.jpg"></div>
<div id="store">
<div id="start">
<img src="img/img01.jpg">
</div>
<div>
<img src="img/img02.jpg"> //wanted to place into "act"
</div>
<div id="end">
<img src="img/img03.jpg">
</div>
</div>
Use nextElementSibling, nextSibling could be a text node
function inner(){
var abc = document.getElementById("start").nextElementSibling;
document.getElementById("act").innerHTML = abc.innerHTML;
}
FIDDLE
If you target browser doesn't support nextElementSibling you can traverse the siblings and find the first element node.
function nextElementSibling(element) {
while (element.nextSibling){
element = element.nextSibling;
if (element.nodeType == Node.ELEMENT_NODE){
return element;
}
}
return undefined;
}
FIDDLE
You have to make sure to skip over whitespace when traversing nodes.
function next(elem) {
do {
elem = elem.nextSibling;
} while (elem && elem.nodeType != 1);
return elem;
}
function inner(){
var abc = next(document.getElementById("start"));
document.getElementById("act").innerHTML = abc.innerHTML;
}
You can see a working example at http://jsfiddle.net/CkCR3/.
The cause of this behaviour is white space between div with id "start" and the following div. So, nextSibling will be text content. You need to do nextSibling twice:
var abc = document.getElementById("start").nextSibling.nextSibling;
Another option is to remove whitespace characters between two divs.
Please change your line of code as per below;
because every next element is check for exists or not ,then get inner html.
function inner() {
var abc = document.getElementById("start");
do {
abc = abc.nextSibling;
} while (abc && abc.nodeType != 1);
document.getElementById("act").innerHTML = abc.innerHTML;
return false;
}
I've made a jsfiddle to demonstrate an easier way.
You'll notice that the act div is red and that the start div is blue. The innerHTML will change when you click the button. Also, a reason that you might see undefined is because the DOM didn't load and so it doesn't have any idea that the divs exist. Next time you should use window.onload = inner(); to make the function run after the DOM has loaded.
This is the jsfiddle: http://jsfiddle.net/yY9Ag/16/
there are two way
first fix the code
nextSibling.nextSibling.innerHTML
or fix the html : remove all \n char
<img id="btnRight" src="img/btnRight.png" onclick="inner()"><div id="act"><img src="img/home01.jpg"></div><div id="store"><div id="start"><img src="img/img01.jpg"></div><div><img src="img/img02.jpg"> //wanted to place into "act"</div><div id="end"><img src="img/img03.jpg"></div></div>
because div tag's next sibling is empty textNode (it can't see)