Lots of empty lines in the DOM - javascript

When I read .html() at the end of this snippet, I get this result :
"
<div style="left: 0px;" class="text">Test1</div><div style="left: 1px;" class="text">Test2</div><div style="left: 2px;" class="text">Test3</div>"
Why all these empty lines?
Note: in the JS part, I detach all the .text elements, apply some modifications on them, and reappend them to the DOM. I need to do that in my real code, for some reasons that would be out of topic here.
$("#blah").append($(".text").detach().each(function(i) {
this.style.left = Math.random() * 10 + 'px'; this.style.top = i*10 + 'px';
}));
console.log($("#blah").html());
.text {position:absolute;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<body>
<div id="blah">
<div class="text" >Test1</div>
<div class="text" >Test2</div>
<div class="text" >Test3</div>
</div>

You do not need to the detach and append the elements to change their style. You are basically accumulating all the whitespace between elements at the top and moving all the elements below the whitespace.
If your HTML looked like this the problem would not have been visible:
<div id="blah"><div class="text" >Test1</div><div class="text" >Test2</div> <div class="text" >Test3</div></div>
JSFiddle: http://jsfiddle.net/TrueBlueAussie/not1yerc/
Basically do not detach and append. The changes occur on the same JS browser cycle so will not glitch:
$(".text").each(function(i) {
this.style.left = Math.random() * 10 + 'px'; this.style.top = i*10 + 'px';
});
console.log($("#blah").html());
The real problem:
As the real problem is using detach and append to avoid transition-delay styling from firing, the real solution is to remove a specific transition class from the elements, change them, then add that class back.
e.g. have a new transitions class with the transitioning styles:
.transitions{
transition-duration: 0.2s;
}
make sure all your text elements have that class as required. Then your code becomes:
$(".text").each(function(i) {
// Remove the transitions styling class
$(this).removeClass('transitions');
// Change the layout without transitions
this.style.left = Math.random() * 10 + 'px'; this.style.top = i*10 + 'px';
// Restore the transitions styling class
$(this).addClass('transitions');
});
This is much faster than detach and appending DOM elements and will not move the whitespace.

Why all these empty lines?
Because they were in your initial DOM before you moved around nodes. If you have a look at the html source of #blah, you'll find four linebreaks - which are represented in the DOM as whitespace text nodes. Since you didn't remove them, they still reside in the DOM - only with no more <div>s in between them, making the lines empty.

You have empty lines because of the whitespace in your markup. Also, as mentioned by others in comments, you don't need to detach. If you don't want to change your markup, then do a .trim().
Sample Snippet:
$("#blah").find(".text").each(function(i) {
this.style.left = Math.random() * 10 + 'px'; this.style.top = i*10 + 'px';
$(this).appendTo($("#blah"));
});
console.log($("#blah").html().trim());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="blah">
<div class="text" >Test1</div>
<div class="text" >Test2</div>
<div class="text" >Test3</div>
</div>
Alternatively, just remove the whitepsace from your markup in this case. As #trueblueassie mentioned, .trim() could be slow for large chunk of HTML string. And, then you don't even need to .append() to move things around.
<div id="blah"><div class="text" >Test1</div><div class="text" >Test2</div><div class="text" >Test3</div></div>

Related

Javascript: Delete a div that contains (3) in a row <BR>'s in it

<div>
<br>
<br>
<br>
</div>
I have an HTML page that has the above div element in it. How can I scan the page an look for a DIV that contains specific items? In this example I know I have three <br> in a row and that's it. The DIV element does not have a class or an ID, and I would like to delete it.
You can target elements in a row by using the sibling selector, +. You can make sure the target elements are a direct child of the div by using the > selector.
You can find the div that contains the three br elements like so:
document.querySelector('div > br + br + br').parentNode;
To remove this element from the DOM use the remove method.
const elToDelete = document.querySelector('div > br + br + br')?.parentNode;
elToDelete?.remove();
Edit:
Added optional chaining syntax to the answer to show how to prevent undefined errors from being thrown.
You can use the :has pseudo-class to select the div directly
var elem = document.querySelectorAll("div:has(>br+br+br)");
console.log([...elem])
elem.forEach(x=>x.remove())
<div id=a> a
<br/>
<br/>
<br/>
</div>
<div id=b> b
<br/>
<br/>
</div>
<div id=c> c
<br/>
<br/>
<not-br/>
<br/>
</div>
You can try this:
[].slice.call(document.getElementsByTagName("div")).forEach(function(div){
var count = 0;
if(div.children.length === 3)
[].slice.call(div.children).forEach(function(br, i){
if(br.nodeName === "BR")
count++;
});
if(count > 2)
div.parentElement.removeChild(div);
});
You can just hide it with CSS
div:has(>br+br+br) {
display: none;
}
<div>1</div>
<div><br/><br/><br/></div>
<div>3</div>
Best solution that will work cross-browser is to tackle this programmatically. Note that :has() pseudo class doesn't work on Firefox, IE or Opera (see https://caniuse.com/css-has).
Here's a concise functional Javascript approach:
[].filter.call(document.querySelectorAll('div'), el => el.querySelectorAll('br').length === 3)

Positioning a div at co-ordinates of another div

I have a div inside which I have an anchor tag, on click of anchor tag I take its co-ordinates and using javascript I position another div next to it.
Below is my parent div.
<div class="parent1-div>
<div class="parent2-div>
<div class="child-div">
<a (click)="anchorClickEvent($event)"></a>
</div>
</div>
</div>
This is another div, which I have kept separate so it can used elsewhere also,
<div class="movable-div" [ngStyle]="{'left': xPosition, 'top': yPosition}">
This div contains some crazy animation
</div>
On click event:
anchorClickEvent(event: Event){
this.xPos = event.currentTarget['x'] - somePx + 'px';
this.yPos = event.currentTarget['y'] - somePx + 'px';
}
This gives me position relative to whole body, but I need the position of 'child-div' with respect to 'parent-div1', so I can set those position to 'movable-div'.
Inputs are appreciated.
Solved my issue:
On click event I got the offset of anchor tag and subtracted offset of top most container i.e, 'parent1-div'.
anchorClickEvent(event: Event){
this.xPos = Math.round(event.srcElement.getBoundingClientRect().left) - Math.round(event.srcElement.closest('.parent1-div').getBoundingClientRect().left) + 'px';
this.yPos = Math.round(event.srcElement.getBoundingClientRect().top) - Math.round(event.srcElement.closest('.parent1-div').getBoundingClientRect().top) + 'px';
}
And added these styles dynamically to 'movable-div' element, which is position absolute relative to body.
<div class="movable-div" [ngStyle]="{'left': xPos, 'top': yPos}">
This div contains some crazy animation
</div>

Javascript align vertical center many child divs within parent

Trying to dynamically resize the div (col with pad) with JavaScript so that it is vertically middle of the parent div (row).
The text blocks vary in size as do the images and there are many of these divs within the page.
I'm quite close to achieving this with the provided code, but the loop seems to be repeating more times than it should and sets the height incorrectly on the last pass, almost like it is halving the space over and over again.
Is there a way to make the JavaScript only run once?
<div class="row">
<div class="col pad">
<p>Text here</p>
</div>
<div class="col">
<img src="image.jpg">
</div>
</div>
$(window).load(function(){
$('.row').each(function() {
var parentDiv = $(this).height();
$('.pad').each(function() {
var childDiv = $(this).height();
var space = parentDiv - childDiv;
var half = space/2;
$(this).css('paddingTop', half + 'px');
alert(half);
});
});
});
I'm unable to use css to achieve this as col are floated.

How to make text hidden or revealed when inside or outside a <div>?

I have some text like this:
Once upon a time, <div class="light">there lived</div> a cat.
The <div class="light">cat liked</div> to watch fish swim.
I need to place some text, in a <div> e.g. <div class="hidden_when_inside">text</div> which is hidden if placed inside <div class="light">, but not hidden when outside. E.g.:
Once upon a time, <div class="light">there <div class="hidden_when_inside">this text is invisible</div> lived</div> a cat.
The <div class="light">cat liked</div> to watch <div class="hidden_when_inside">this text is visible</div>fish swim.
Similarly, some text placed in <div class="hidden_when_outside"> will be hidden only when outside of <div class="light">.
Here hidden means:
The text cannot be seen.
The text cannot be selected.
The text occupies no space.
The text does not interfere with the formatting of the other text.
Is there any way to hide or reveal text depending on whether or not it appears within another <div>?
Use the parent selector to hidden the inside element like below.
.light .hidden_when_inside{display:none}
FIDDLE DEMO
This can be done using pure css using the child selector > (note this will only effect immediate children so if the use case is that .hidden_when_inside can be nested several layers deep inside a .light then go with .light .hidden_when_inside)
.light > .hidden_when_inside{
display:none
}
Once upon a time, <div class="light">there <div class="hidden_when_inside">this text is invisible</div> lived</div> a cat.
The <div class="light">cat liked</div> to watch <div class="hidden_when_inside">this text is visible</div>fish swim.
If you want to display it later, you need to dive into JavaScript, for instance:
document.getElementByTagName('hidden_when_inside').onclick = function() {
var className = ' ' + myButton.className + ' ';
this.className = ~className.indexOf(' active ') ?
className.replace(' active ', ' ') :
this.className + ' active';
}

Adding variable heights with multiplier in jQuery

The following code does what it should perfectly, however I need to add 30% more height to the containing element .boxy on top of the added variable heights.
I've tried searching for ways to add a percentage to the equation, but so far I've just found vague answers or non-applicable methodologies.
$(".exPand a").click(function (event) {
event.preventDefault();
var postHeight = $(this).closest('.boxy').find('.articleImageThumb').height();
var excHeight = $(this).closest('.boxy').find('.initialPostLoad').height();
$(this).closest('.boxy').animate({height: postHeight+excHeight}, 1000);
});
Live output:
<div class="boxy">
<div class="boxGrad"></div>
<div class="postmetadata"></div>
<div class="articleTitle"></div>
<div class="rightCtrls"></div>
<div class="ajaxBoxLoadSource"></div>
<div class="articleImageThumb"></div>
<div class="initialPostLoad"></div>
</div>
Just multiply by 1.3
$(this).closest('.boxy').animate({height: (postHeight * 1.3)+excHeight}, 1000);
Move the * 1.3 to the appropriate place depending on which height you want 30% of.

Categories