CSS nth-child doesn't work on dynamically hidden element [AngularJS] - javascript

I'm trying to implement CSS nth-child on every number of elements. If a certain number is reached I want to hide the first element and make it reappear if the number reduces again.
The problem is that somehow the nth-child still counts the hidden element and thus wrongly implements the styling. Is this a bug or am I doing it wrong?
NOTE: The same thing also happens if I use jQuery
http://jsfiddle.net/bedex78/uZ5wn/23/
The View:
<div ng-app>
<div ng-controller="TheCtrl">
<p>Amount to add: <input type="text" ng-model="amount" ng-init="amount=1"></p>
<div class='holder'>
<div ng-class='elements.length < 6 ? "inside" : ""'
ng-hide="elements.length >= 6">
<button class='button' ng-click="add(amount)">Add more</button>
</div>
<div class='inside' ng-repeat="(k,v) in elements">
{{ $index }} Remove
</div>
</div>
</div>
</div>
The JS (AngularJS):
function TheCtrl($scope) {
$scope.elements = [{id:1},{id:2}]
$scope.add = function(amount) {
for (i=0; i < amount; i++){
$scope.elements.push({id:$scope.elements.length+1});
}
};
$scope.remove = function(index) {
$scope.elements.splice(index, 1);
};
}
The CSS:
.holder {
width: 300px;
height: 400px;
border: 1px solid black;
}
.inside {
height: 30px;
border: 1px solid black;
}
.inside:nth-child(3n+1) {
background-color: yellow;
}
.inside a {
float: right;
}

It happens because hidden element is still in DOM. So it is count as a child and styles applied accordingly.
You can try to use ng-if instead of ng-hide. It will make div disappear from DOM and styles will work fine.
Example

Related

Show content of 2 divs with same div class name, using onclick

I need to make 2 div content visible by pressing a button.
I do not use "getElementsById" since the Id should be unique. The divs will be in different location so I cannot wrap then with another div.
I am aiming of using plain JS.
Background for doing this is to have a button for demos where one iframe will show an app, and the other iframe will show the app description. The button click should therefor activate 2 divs (that are spreadout in the code).
function display_both_divs() {
document.getElementsByClassName('boxes').style.display = "block";
}
body {
background-color: pink;
}
.boxes {
display: none;
}
.button {
width: 200px;
height: 60px;
}
<button
class="button"
type="button"
name="button"
onclick="display_both_divs()"
> Show boxes content
</button>
<div class="boxes">box_1</div>
<div class="boxes">box_2</div>
You need to loop over the elements retrived by getElementsByClassName:
function display_both_divs() {
Array.from(document.getElementsByClassName('boxes')).forEach(e => e.setAttribute('style','display:block'));
}
body {
background-color: pink;
}
.boxes {
display: none;
}
.button {
width: 200px;
height: 60px;
}
<button
class="button"
type="button"
name="button"
onclick="display_both_divs()"
> Show boxes content
</button>
<div class="boxes">box_1</div>
<div class="boxes">box_2</div>
look here: JS: iterating over result of getElementsByClassName using Array.forEach
You could put both the div within another div and set show/hide that div using unique id
HTML
<div id="superbox">
<div class="boxes">box_1</div>
<div class="boxes">box_2</div>
</div>
Script
function display_both_divs() {
document.getElementById('superbox').style.display = "block";
}
You can do this using JQuery.
function display_both_divs() {
$('.boxes').css('display','block')
}
body {
background-color: pink;
}
.boxes {
display: none;
}
.button {
width: 200px;
height: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button
class="button"
type="button"
name="button"
onclick="display_both_divs()"
> Show boxes content
</button>
<div class="boxes">
<div>box_1</div>
<div>box_2</div>
</div>
Seems the most straightforward way is to utilize the fact that [getElementsByClassName] returns an array. I can then specify each div named boxes. No loops, no frameworks needed:
function display_both_divs() {
document.getElementsByClassName('boxes')[0].style.display = 'block';
document.getElementsByClassName('boxes')[1].style.display = 'block';
}

Limit selectable divs in a parent div

I'd like to create a product feature selection page where the user needs to select 3 features out of 6. Now, I got to a point where I can limit the number of selectable elements so if 3 elements are selected, the user wont be able to select a 4th one.
I need to modify this so when the user is attempting to select the 4th element, the 1st element they selected becomes unselected and the 4th element becomes selected. I hope it makes sense.
$('div').click(function(e) {
var $et = $(e.target);
if ($et.hasClass('fill')) {
$et.removeClass('fill');
} else {
if ($('.fill').length < 2) {
$et.addClass('fill');
}
}
});
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
This fiddle shows where I'm at with my code: http://jsfiddle.net/MarKP/32/
This fiddle is not mine, but this is exactly what I have right now in my project.
I'm trying to get this done using jQuery or plain JavaScript.
Thank you in advance!
To achieve this you can maintain an array which holds the order in which the elements were clicked. Then, when the limit is hit, you can remove the class from the element which was selected first. Try this:
var selections = [];
var $div = $('div').click(function(e) {
selections.push(this.id);
if (selections.length > 3)
selections.shift(); // remove first item
setState();
});
function setState() {
$div.removeClass('fill');
$div.filter(`#${selections.join(',#')}`).addClass('fill');
}
div {
border: 1px solid blue;
height: 25px;
margin-bottom: 5px;
}
.fill {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="1">one</div>
<div id="2">two</div>
<div id="3">three</div>
<div id="4">four</div>
<div id="5">five</div>
<div id="6">six</div>
Finally, note that jQuery 1.4.4 is massively outdated; nearly 10 years in fact. You need to update it.

Reset Border style

I have a image that is currently being styled with Jquery once it's clicked. I eventually hide it in Javascript. I want to reshow it, but I want it to have the border removed.
Here is HTML:
<div id="playOptionsWager" style="display: none">
<h4>Choose your move to beat the computer!</h4>
<img id="clickedRockWager" src="img/rock.jpg" onclick="playWagerRock()" />
<img id="clickedPaperWager" src="img/paper.jpg" onclick="playWagerPaper()"/>
<img id="clickedScissorsWager" src="img/scissors.jpg" onclick="playWagerScissors()" />
</div>
Jquery:
$(function () {
$("img").on("click",function() {
$(this).siblings().css('border','0px')
$(this).css('border', "solid 2px red");
});
});
Here is what I was trying in Javascript:
function autobet() {
coinBalance -= currentBet*2;
alert(getBalance());
document.getElementsByTagName("IMG").style.border="";
}
However when it reshows the div it has the border on it still.
Thanks for the help!
Your issue is that document.getElementsByTagName("IMG") returns a collection of elements, so simply applying .style.border on this collection won't work. Instead, you need to loop over this collection, and set every image within it to have no border using .style.border = 0;:
See working example (with div) below:
function removeBorder() {
[...document.getElementsByTagName("div")].forEach(elem => {
elem.style.border = 0;
});
}
.box {
height: 100px;
width: 100px;
background: black;
display: inline-block;
}
.active {
border: 3px solid red;
}
<div class="box"></div>
<div class="box active"></div>
<div class="box"></div>
<br />
<button onclick="removeBorder()">Remove border</button>
Also note that [...document.getElementsByTagName("IMG")] is a way of converting the collection of elements into an array of elements, which thus allows us to use the .forEach method to loop over it.
You started with jQuery, let's continue with jQuery.
function autobet() {
coinBalance -= currentBet*2;
alert(getBalance());
$("img").css("border","");
}
The problem is that getElementsByTagName() returns a collection not one element.
First you need to iterate over the collection of html elements you have - when using getElementsByTagName you get back an array of elements.
Second you need to give the elements a style of zero.
const divElements = document.getElementsByTagName("IMG");
for (let i=0; i < divElements.length; i++) {
divElements[i].style.border = 0;
}
You can see the code on stackbliz -
https://stackblitz.com/edit/border-issue?file=index.js

Sort Divs by inline "style" attribute

Is it possibile to sort divs by an inline width attribute (highest first)?
For example that are my divs:
<div style="width: 30.8px"></div>
<div style="width: 10.45px"></div>
<div style="width: 20px"></div>
I was looking for something like this, but it only works with div content ;(
$('.list li').sort(sortDescending).appendTo('.list');
function sortDescending(a, b) {
var date1 = $(a).find("div").text()
var date2 = $(b).find("div").text();
return $(b).find("div").text() - $(a).find("div").text();
};
It would be easier to just sort by the width of the element itself. This has two benefits; firstly you don't have to dissect the string to get the width value and secondly (and more importantly) you can then set the width property in an external stylesheet and the logic will still work. Try this:
$('div').sort(function(a, b) {
return $(a).width() > $(b).width() ? -1 : $(a).width() < $(b).width() ? 1 : 0;
}).appendTo('.list');
div div {
border: 1px solid #C00;
margin: 5px;
height: 5px;
}
#foo {
width: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="list">
<div style="width: 30.8px"></div>
<div style="width: 10.45px"></div>
<div style="width: 20px"></div>
<div id="foo"></div>
</div>
Note that your selector is aiming for li elements yet your sample is using div elements. I'm just presuming this is just an oversight when writing the question.

jQuery :has selector filter trouble

I have some containers with ids="container1", "container2", "container3"...
They can have one of two types of tags inside: tables or canvas.
I want to hide one of them depending on the device orientation.
I have tried with this
$('[id^=container]:has(canvas)').hide();
or
$('[id^=container]:has(table)').hide();
but both hide all the containers, don't filtering their inside tags.
You can do
var x = $('[id^=container]').find("table").length;
// Will be 0 if no table inside it
if(x==0) { .. }
else { .. }
You can use classes on your containers instead of ids. Here's a JSFiddle demo.
For better performance in modern browsers, use $( "your-pure-css-selector" ).has( selector/DOMElement ) instead.
Source: https://api.jquery.com/has-selector/
Basically I made a 3 containers. One with a table, one with a canvas and one with nothing.
<div class="container green">
<table></table>
</div>
<div class="container blue">
<canvas></canvas>
</div>
<div class="container red"></div>
And a quick CSS to have the divs visible.
div.container{
display: inline-block;
height: 50px;
margin: 10px;
width: 50px;
}
div.green{
background-color: green;
}
div.blue{
background-color: blue;
}
div.red{
background-color: red;
}
And to complete it, a jQuery that executes when the document is ready.
$(document).ready(function(){
$('div.container').has('canvas').hide();
});
If you know the element by which you want to grab the container is not nested within additional tags, you can use the parentNode property of an HTML element to climb up the DOM tree and hide the parent.
document.querySelector("[id^=container] > table").parentNode.style.display= "none";
Example that demos the concept:
document.getElementById("input").addEventListener("change", function() {
document.getElementById("container1").style.display = "block";
document.getElementById("container2").style.display = "block";
document.querySelector("[id^=container] > " + this.value).parentNode.style.display = "none";
});
#container1 {
border: 1px solid red;
}
#container2 {
border: 1px solid blue;
}
<select id="input">
<options>
<option value="table">Hide the table</option>
<option value="canvas">Hide the canvas</option>
</options>
</select>
<div id="container1">Table
<table></table>
</div>
<div id="container2">Canvas
<canvas></canvas>
</div>
I didn't realized I had a global container with id= "container*".
What a silly mistake. Sorry for stealing your time, and thank you everyone!

Categories