How to find visible child in hidden parent - javascript

I want to show a div which has the error message span visible in it. I tried the following codes but it works only when the container is visible otherwise it is unable to find in it.
Can someone share the reason and solution to it?
Code 1:
Using .length
$(".has-warning:visible").each(function() {
var id = this.id;
var divs = ["wReq_div", "mcatIsq_div", "glDetail_div"];
for (var i = 0; i < divs.length; i++) {
if ($("#" + divs[i] + " #" + id).length) {
console.log("found in " + divs[i]);
return false;
}
}
});
This gives true for the container if it's visible otherwise not.
Code 2:
Using $.contains
$(".has-warning:visible").each(function(){
var id = this.id;
var divs = ["wReq_div","mcatIsq_div","glDetail_div"];
for(var i=0;i<divs.length;i++){
if($.contains($("#"+divs[i])[0],$("#"+id)[0])){
console.log("found in " + divs[i]);
return false;
}
}
});
It's also working only if the container is visible.
So my main problem is:
Parent is hidden and child has display not none, how to find that shown child in the hidden parent
To find that which parent div(hidden) has an error div with given id so that I can show that parent div.
Here is the CodePen
I don't want to use the method of changing class from a hidden one to visible one to display my errorMsg as I'll have to do a lot of changes in multiple files.

From the docs
jQuery( ":visible" )
Elements are considered visible if they consume space in the document. Visible elements have a width or height that is greater than zero.
If a parent is hidden, all it's children will also be hidden. So, $(".has-warning:visible") will not return the child elements, even if they're not hidden.
you need to rely on the display property of the child elements, rather than the :visible attribute and try something like this,
function checkMsg1(){
$(".has-warning").each(function() {
var id = this.id;
var i=0;
var divs = ["wReq_div", "mcatIsq_div", "glDetail_div"];
for (i = 0; i < divs.length; i++) {
if ($("#" + divs[i] +" #"+id).css("display") !== 'none') {
$("#" + divs[i]).show();
}
}
});
}

I used following code to overcome this problem, Please suggest if you have better one:
var divs = ["wReq_div","mcatIsq_div","glDetail_div"];
$(".has-warning").each(function(){
if($(this).css("display") != "none"){
var id = this.id;
for(var i=0;i<divs.length;i++){
if($.contains($("#"+divs[i])[0],$("#"+id)[0])){
console.log("found in " + divs[i]);
break;
}
}
}
});
But it first selects all the divs and may increase time.

you will not find .has-warning:visible as its parent is not visible. But you can check for parent div if it is hidden or not.
$(".has-warning").each(function() {
if($(this).css("display") != "none"){
var id = this.id;
var i=0;
var divs = ["wReq_div:hidden", "mcatIsq_div:hidden", "glDetail_div:hidden"];
for (i = 0; i < divs.length; i++) {
if ($("#" + divs[i] + " #" + id).length) {
alert("found in " + divs[i] + " " + id);
// Add code to display that div
}
else {
alert("not found in " + divs[i]+ " " + id);
}
}
}
});

Related

Sort divs (added dynamically) by classname

I have been struggling to find a way in which I could sort Divs after being displayed .So far, I have used prepend() and append() and I have managed to show at first the players that are streaming, but the next divs are random. I want to be able to show who's online, who's not and who has closed the account in order.
I have already tried deferred method: $.when(makeDivs()).then(sortDivs());
but it's not working properly, any idea how I can fix this?
My codepen: http://codepen.io/diegomdzr/pen/vKWGbd
I don't have the reputation to comment yet. But from my understanding, you want to make the classNames of divs in alphabetical order after they have been applied to the document?
function reOrder() {
var div = document.getElementsByTagName('div');
var cn = []; //ClassNames of each div.
for (var i = 0; i < div.length; i++) {
cn.push(div[i].className);
}
cn = cn.sort(); //sort the array in alphabetical order.
var oDiv = [];
for (var i = 0; i < cn.length; i++) {
//for each array item in cn, find where it's element is, remove the element, continue.
for (var ii = 0; ii < div.length; ii++) {
if (div[ii].className == cn[i]) {
oDiv.push(div[ii]);
var newDiv = [];
for (var iii = 0; iii < div.length; iii++) {
//Remove the element from the array.
if (div[iii] != div[ii]) {
newDiv.push(div[iii]);
}
}
div = newDiv;
}
}
}
return oDiv;
};
reOrder();
This will return an array of the elements, but sorted. You can then replace all of the elements of the document with these sorted elements.
Sorting is expensive, should be avoided if possible, and isn't a particularly good solution here.
It's way simpler to create a container (div) for each of your streamer categories, (online|offlie|nonExistent) then simply append HTML, as it is generated, to the appropriate container.
$(document).ready(function() {
var streamers = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas", "comster404", "brunofin", "HorussTV"];
var link = "https://twitch.com/";
// Create/append containers here (or hard-code them in HTML) ... in correct order of presentation within #streamers.
var $onlineStreamers = $("<div/>").appendTo($('#streamers'));
var $offlineStreamers = $("<div/>").appendTo($('#streamers'));
var $nonExistantStreamers = $("<div/>").appendTo($('#streamers'));
streamers.forEach(function getStatus(element) {
$.getJSON("https://api.twitch.tv/kraken/channels/" + element + "?callback=?", function(json) {
var img = json.logo || "http://res.cloudinary.com/djnwhbm1z/image/upload/v1468187598/unknown_i7m43p.png";
$.getJSON("https://api.twitch.tv/kraken/streams/" + element + "?callback=?", function(json) {
// Append HTML to the appropriate container
if(json.stream) {
$onlineStreamers.append('<div class="online"><h4>' + element + '</h4><img src="' + img + '" class="profPic"><div class="content text-center"><span><b>Game:</b></br>' + json.stream.game + ' </br><b>Status: </b>' + json.stream.channel.status + '</span></div></div>');
} else if(json.status == 422) {
$nonExistantStreamers.append('<div class="nonExistant"><h4>' + element + '</h4><img src="' + img + '" class="profPic"><div class="content text-center"><span>Account Closed</span></div></div>');
} else {
$offlineStreamers.append('<div class="offline"><h4>' + element + '</h4><img src="' + img + '" class="profPic"><div class="content text-center"><span>Offline</span></div></div>');
}
});
});
});
});
Notes:
No sorting required unless the entries need to be sorted within each category.
You can probably purge class="online" etc from the appended HTML, unless those classes are used elsewhere.

Cloning a div using a For-Loop isn't giving the right amount of clones

I am trying to make a script that will clone a div, cards in bootstrap 4, and change text in the div. I want this to happen a certain number of times., depending on the variable. However, when I use the script below I'm getting 8 cards (7 clones), instead of the 3 clones that it is supposed to be making. Does anyone know what is happening here?
$(document).ready(function(){
var cards = 3;
var id = "";
var newClass = "";
var i;
for(i = 0; i < cards; i++) {
id = id + "1";
newClass = newClass + "1"
$(".listings").clone().addClass(newClass).appendTo("body");
$("."+newClass).attr("id",id);
$("#" + id + " " + "h1").text("$5000");
}
});
change
.addClass(newClass)
to
.prop("class",newClass)

Dynamic generation of select clear other elements in javascript

I have a for loop that creates as many as I write in an input field. first time I write a number in the imput all is ok... he generates for example 3 fields. When I delete 3 and write 5, he add two objects but he also clear other... if I select an option in the first , I want to keep it selected when I add some other fields....
this is an example: https://jsfiddle.net/exv8s2sq
and this is the code:
Insert number<input type="text" id="number" name="number" ><br><br>
<div id="container"></div>
<script>$('#number').on('keyup', function () {
changenumber(this.value);
});
$('#number').on('paste', function () {
changenumber(this.value);
});
var now = 0;
function changenumber(val) {
container = document.getElementById("container");
var diff = val - now;
if (diff > 0) {
for (var u = now + 1; u <= val; u++) {
container.innerHTML = container.innerHTML +
" Select from options <select id='selectobj" + u + "' name='selectobj" + u + "' style='width:25%;'>" +
"<option>A</option>" +
"<option>B</option>" +
"<option>C</option>" +
"</select><br><br>";
now = u;
}
}
}</script>
thanks
Lorenzo from Rome
Instead of using innerHTML, i would suggest using jQuery as selector and use element.append(selectbox) to add new items. I've updated your fiddle with a working example based on your code:
http://jsfiddle.net/exv8s2sq/1/
There is also room to refactor your code a bit. When using jQuery, native javascript isn't really necessary for dom manipulation.
Wrap your elements in a div with a specific class so you can easily count how many items you already have. Then depending on the number you enter, check whether you need to add or remove elements from your container.
Use jQuery selectors all the way, it is easier to identify your elements, and use the methods it provides such as .each() and .append()
$('#number').on('input', function () {
changenumber(this.value);
});
function changenumber(val) {
if (val !== '') {
// Wrap your elements in a div with a specific class
var select = '<div class="select-wrapper">Select from options <select><option>A</option><option>B</option><option>C</option></select></div>';
// Count number of selects div
var nbOfSelects = $('.select-wrapper').length;
// Check if you need to add or remove elements
if (nbOfSelects < val) {
// Add an element
for (var i = 0; i < (val - nbOfSelects); i++) {
$('#container').append(select);
}
} else {
// Loop through elements
$('.select-wrapper').each(function (i) {
// Remove an element
if (i >= val) {
$(this).remove();
}
});
}
}
}
JSFiddle demo
Try this, it adds an attribute of selected to the previous selected option using an onchange event listener
$('#number').on('keyup', function () {
changenumber(this.value);
});
$('#number').on('paste', function () {
changenumber(this.value);
});
var now = 0;
function changenumber(val) {
container = document.getElementById("container");
var diff = val - now;
if (diff > 0) {
for (var u = now + 1; u <= val; u++) {
container.innerHTML = container.innerHTML +
" Select from options <select onchange='updateDom(this)' id='selectobj" + u + "' name='selectobj" + u + "' style='width:25%;'>" +
"<option>A</option>" +
"<option>B</option>" +
"<option>C</option>" +
"</select><br><br>"; now = u;
}
}
}
function updateDom(s){
s.options[s.selectedIndex].setAttribute("selected","selected")
}

Looping through an array with CSS rules, and applying them to element

I want users to be able to input CSS input, and have that CSS applied to the last selected element(selected by the "rangeselector" variable). The code selects the right element, but only the first CSS-rule is applied.
ex: "background: blue; color:red;" only applies the background.
The function runs through the array correctly.
function customCss(){
css = $("input.css").val();
if(css.length < 10){
alert("Insert valid CSS");
}else{
cssArray = css.split(";");
counter = 0;
cssArray.forEach(function(){
var ruleSplit = cssArray[counter].split(":");
target = $("[content_child=" + rangeselector + "]");
target.css(ruleSplit[0] , ruleSplit[1]);
counter = counter + 1;
});
}
}
If you know the problem, or have a better way of achieving the same goal, i would gladly hear you suggestions.
Thanks
By using Array.forEach() you already have the index and the reference to Array. You don't need use a counter
cssArray = css.split(";");
// counter = 0;
cssArray.forEach(function(obj, key, array){
var ruleSplit = obj.split(":");
target = $("[content_child=" + rangeselector + "]");
target.css(ruleSplit[0] , ruleSplit[1]);
// counter = counter + 1;
});
have you tried stripping the elements before you set them? What's probably happening is that it's trying to set something like "color " instead of "color"
function customCss(){
css = $("input.css").val();
if(css.length < 10){
alert("Insert valid CSS");
}else{
cssArray = css.split(";");
counter = 0;
cssArray.forEach(function(){
var ruleSplit = cssArray[counter].split(":");
target = $("[content_child=" + rangeselector + "]");
target.css(ruleSplit[0].trim() , ruleSplit[1].trim());
counter = counter + 1;
});
}
}

How to replace text on an click event using jquery

Here when i click on a particular player its score is displayed.But when again a player is clicked the previous score doesn't get cleared.So pls can anyone provide the solution.
$(document).ready(function () {
for (var i = 0; i < temp.length; i++)
$("#sidebar").append("<div id=" + i + " class='player'>" + temp[i].name + "</div>")
$(".player").click(function () {
var pla = $(this).attr('id');
$("#score").append(temp[pla].score);
//$(".content").append(a[pla].Events);
var selected = $(this).hasClass("highlight");
var a = $("span").append($(this).text());
$(".player").removeClass("highlight");
if (!selected) {
$(this).addClass("highlight");
$(this.Text()).remove();
}
});
});
You might need to add a call to .html() for the sidebar to clear its content, add it at the top of your document ready function.
So something like:
$("#sidebar").html();

Categories

Resources