Styling Elements that have been appended using jquery - javascript

I have div elements that are appended on a parent div. Depending on the screen size, the div elements should resize but my efforts to do so using jquery .css() are failing all through. Kindly help. Below is a sample of my code
var len = data.length; //a number comes here
var i;
for(i=1;i<len+1;i++){
$(".app-body").append(
"<div class='list-box' onclick='OpenHymn("+ i +")'>" +
"<div class='circle-text'><div class='hym_num'>" + i + "</div></div>" +
"</div>");
}
//calling the function that should resize the divs
GridBoxes();
function GridBoxes(){
var width=window.innerWidth;
var divisible=parseInt(width-40);
var size=divisible/4;
var boxes=$('.list-box');
boxes.css("width",size+"px");
boxes.css("height",size+"px");
}

Put the function inside $(window).resize() for it to fire everytime the window is resized
Code:
$(window).resize(function() {
GridBoxes();
})
Example
You should really use media query's for this kind of problem.

try this
window.addEventListener("resize", GridBoxes);//called on window resize
var len = 4; //changed to a number here for testing
var i;
for(i=1;i<len+1;i++){
$(".app-body").append(
"<div class='list-box' onclick='OpenHymn("+ i +")'>" +
"<div class='circle-text'><div class='hym_num'>" + i + "</div></div>" +
"</div>");
}
//calling the function that should resize the divs
//GridBoxes();
function GridBoxes(){
var width=window.innerWidth;
var divisible=parseInt(width-40);
var size=divisible/4;
var boxes=$('.list-box');
for(var b=0;b<boxes.length;b++){
boxes[b].css("width",size+"px");
boxes[b].css("height",size+"px");
}
}
.list-box{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="app-body"></div>

Related

Jquery change color of SVG element using jscolor.js is failing

I have a web page in which SVG is embedded. I am pulling references of elements of SVG and creating color swatches for every element using jscolor.js library.
I want to adjust color of these elements using swatches I am dynamically creating on click jquery event listener.
The problem is, after couple of changes SVG element is becoming black due to some error which is assigning 'undefined' fill color to this SVG element.
I am not getting why it not working all the time.
The main function to do this job is as follows
$("#svg_obj").on("click", ".badge", function(event) {
event.stopPropagation();
var rect = event.target.getBoundingClientRect();
$(".badge").attr('selection', null);
this.setAttribute('selection', true);
var svg_left = ((Math.round(this.getAttribute('width')) - Math.round(this.getBoundingClientRect().width)) / 2);
$(".selector").css("left", Math.round(this.getBoundingClientRect().x - svg_left) + 'px')
$(".selector").css("top", Math.round(this.getBoundingClientRect().y) + 'px')
$(".selector").css("width", Math.round(this.getAttribute('width')) + 'px');
$(".selector").css("height", Math.round(this.getAttribute('height')) + 'px');
$(".selector").css("visibility", "visible");
for (let i = 0; i < this.childNodes.length; i++) {
var svg_g = this.childNodes[i];
// console.log(this.childNodes[i].nodeName);
if (svg_g.nodeName == 'g') {
var polygons = Array.from(svg_g.querySelectorAll("polygon"));
var polygons = polygons.concat(Array.from(svg_g.querySelectorAll("path")));
// console.log(polygons);
Object.values(polygons).forEach(val => {
// console.log(val.attributes.fill.value.substring(1));
console.log(val);
$("#status_bar").append("<p class='swatches " + val.attributes.fill.value.substring(1) + "' >Color:<input data-jscolor='{position:"right"}' value='" + val.attributes.fill.value + "'></p>").on('change', '.' + val.attributes.fill.value.substring(1), function() {
val.attributes.fill.value = $('#status_bar .' + val.attributes.fill.value.substring(1)).find('input').val();
console.log($('.' + val.attributes.fill.value.substring(1)).find('input').val());
});
});
} else {
// console.log("Not a group " +svg_g);
}
}
jscolor.install();
});
jsfiddle for working code
Could you please help to fix this issue?
Thanks

javascript get natural width/height of all images in table

I am trying to get the actual image sizes from the images listed in column Image and display it in column Image Size.
The problem I have is that I am only able to get the size of the first image, which is added in each cell for column Image Size.
jsFiddle: https://jsfiddle.net/a92ck0em/
var xmlFile = 'https://raw.githubusercontent.com/joenbergen/files/master/XMLParse2.xml';
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", xmlFile, true);
xhttp.send();
xhttp.onreadystatechange = function() {
if (this.readyState === 4 && this.status === 200) {
xmlFunction(this.response);
}
};
}
function xmlFunction(xml) {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xml, "text/xml");
var table = "<tr><th>Category</th><th>Title</th><th>Image</th><th>Image Size</th></tr>";
var x = xmlDoc.getElementsByTagName("ITEM");
for (var elem of x) {
var titles = elem.getElementsByTagName(
"TITLE")[0].childNodes[0].nodeValue;
var cats = elem.getElementsByTagName("CATEGORY")[0].childNodes[0].nodeValue;
var imageURL = elem.getElementsByTagName("IMAGE").length === 0 ? "..." : elem.getElementsByTagName("IMAGE")[0].getAttribute('url');
var imageSize = elem.getElementsByTagName("IMAGE").length === 0 ? "..." : elem.getElementsByTagName("IMAGE")[0].width + 'x' + [0].height;
table += "<tr><td>" + cats + "</td><td>" + titles + "</td><td>" + "<img src=" + imageURL + ' height="150" width="100">' + '</td><td id="cellId"><textTag>' + "" + "</textTag></td></tr>";
}
document.getElementById("myTable").innerHTML = table;
document.querySelector("img").addEventListener('load', function() {
var imgTags = document.querySelectorAll('img'), i;
for (i = 0; i < imgTags.length; ++i) {
var image_width = document.querySelector("img").naturalWidth;
var image_height = document.querySelector("img").naturalHeight;
}
$('#myTable textTag').each(function() {
$(this).append(image_width + 'x' + image_height);
//console.log(image_width + 'x' + image_height);
});
});
}
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
th,
td {
padding: 5px;
}
<head>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<button type="button" onclick="loadDoc()">Load</button>
<br><br>
<table id="myTable"></table>
Expected:
Ok there are many parts to your question, I started doing the simplest thing, logging that parsed xml document, looks like this:
...
<IMAGE url="...."></IMAGE>
<IMAGESIZE></IMAGESIZE>
...
So in your script you are getting an attribute that does not exist. So you can safely remove this line:
var imageSize = elem.getElementsByTagName("IMAGE").length === 0 ? "..." : elem.getElementsByTagName("IMAGE")[0].width + 'x' + [0].height;
Next you need to check if the images are loaded, simplest thing to do:
"<img src=" + imageURL + ' height="150" width="100" onload="this._loaded = true;">' +
this will add a proprietary _loaded property to it.
Next you need to check when the images are loaded and once loaded fire a function, you need a recursive function to do that which does not blow the stack:
var imgTags = document.getElementsByTagName('img');
function isLoaded(){
if(Array.prototype.slice.call(imgTags).some(function(d,i){return !d._loaded})){
setTimeout(isLoaded,4);
} else {
$('#myTable textTag').each(function(i,node) {
node.textContent = imgTags[i].naturalWidth + 'x' + imgTags[i].naturalHeight;
//console.log(image_width + 'x' + image_height);
});
}
};
isLoaded();
I removed the querySelectorAll(img) bit, it is slower compared to getElementsByTagName and does not return a LIVE HTML Collection, returns a NodeList. The loaded function will fire your Jquery thing once it detects all the _loaded properties. The Array.prototype.slice.call is an old school way to convert HTML Collection or NodeList to a regular array, the cool kids you Array.from nowadays, it is up to you. You might also optimize the above function a bit by storing the result of Array.prototype.slice.call... once, I leave that to you. All in all it looks like this:
https://jsfiddle.net/ibowankenobi/h9evc81a/
The problem is that you need to wait for the images to load before querying properties like width or height.
Normally this is done by setting an onload event handler that updates the display of these properties.
Moreover you're making a loop setting two variables and then, outside of the loop, you're assigning all the images the value of the very same variables.
You need to do the querying inside the second loop instead.

function firing multiple times when scrolling fast

First of all, I'm not very advanced at code and tend to only do this part time so please excuse all terrible/ugly code! I appreciate there are already some solutions out there but I can't seem to make any of them work with my code so would really appreciate some help!
I'm using isotope grid and trying to setup an infinite scroll. I want to load 10 images at a time when the user scrolls to the bottom by taking these images from an array and appending them to a temp div.
This is working perfectly when scrolling slowly, but as soon as you scroll quickly the function seems to fire multiple times, it gets a little glitchy and loads lots of images at once.
$(window).scroll(function() {
var scrollTop = $(window).scrollTop();
var windowHeight = $(window).height();
var docuHeight = $(document).height();
if(scrollTop + windowHeight == docuHeight){
nextTenImages = imagesData.splice(0,10);
var content = ""
for (var i = 0; i < nextTenImages.length; i++) {
content +=
"<div class='box " + nextTenImages[i]["type"] + "'" + ">" +
"<div class='box-wrapper'>" +
"<img src='" + nextTenImages[i]["src"] + "' />" +
"</div>" +
"</div>"
};
$('body').append('<div id="temp-load"><div id="grid"></div></div>');
$('#temp-load > #grid').append(content)
$('#temp-load > #grid').children().css({
opacity: 0
});
var toAdd = $('#temp-load > #grid').html();
$container.isotope('insert', $(toAdd), function(){
$container.children().css({
opacity: 1
});
$('#temp-load').remove();
});
}
});
Make a single timeout to run the callback. This may avoid the function from executing multiple times.
var timer;
function scrollEvt() {
/* scroll actions */
}
$(window).scroll(function() {
/* clear the old timeout */
clearTimeout(timer);
/* wait until 400 ms for callback */
timer = setTimeout(scrollEvt, 400);
});
Using other ways may result in problems (like comparing (window.performance || Date).now())...
Unbind that specific scroll event till your delayed operation is completed to prevent accumulating more of the event triggers which create the duplication behaviour as in your case.
var winCached = $(window),
docCached = $(document)
var currLeng = 0;
function addContent() {
dettachScrollEvent();
setTimeout(function() { //this timeout simulates the delay from the ajax post
for (var i = currLeng; i < currLeng + 100; i++)
$('div').append(i + '<br />');
currLeng = i;
console.log("called loader!");
attachScrollEvent();
}, 500);
}
function infiNLoader() {
if (winCached.scrollTop() + winCached.height() > docCached.height() - 300) {
addContent();
//alert("near bottom! Adding more dummy content for infinite scrolling");
}
}
function attachScrollEvent() {
winCached.scroll(infiNLoader);
}
function dettachScrollEvent() {
winCached.unbind('scroll', infiNLoader);
}
addContent();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>

jQuery mouseenter only works on first page load

This code presents a grid of colored cells that change color on mouseenter, leaving a trail of cells of the new color. A button reloads the grid with cells of the original color. Problem is the mouseenter color change works only after the first grid load (on page refresh) but not on subsequent loads after the Create New Grid button is clicked.
I am new to javascript and jQuery and though I've been over the class materials and read some articles on how to do various parts of this, I cannot see what is wrong.
Visit the jsfiddle here.
var gridWidth = 600;
var fillGrid = function(){
$('.grid').empty();
var cellsPer = prompt('How many cells would you like in a side?');
console.log('cellsPer = ' + cellsPer);
var cellWidth = (gridWidth / cellsPer) - 1;
console.log('cellSize = ' + cellWidth);
var cell = "<div class='cell'></div>";
for (var i = 0; i < cellsPer**2; i++) {
$('.grid').append(cell);
};
$('.cell').css({
'background':'blue','height': cellWidth+'px', 'width': cellWidth+'px',
'float':'left','margin': '0 1px 1px 0'
});
};
$(document).ready(function() {
fillGrid();
$('.grid').css({'width': gridWidth+'px'});
$('button').click(function(){
fillGrid();
});
$('.cell').mouseenter(function() {
$(this).css('background','pink');
});
});
You where adding the mouseenter event listener only once on $(document).ready.
When fillGrid() gets called, a new set of '.cell' elements not bound to the mouseenter event get added to DOM.
You must tell them to behave the same again.
See the following snipped:
var gridWidth = 600;
var fillGrid = function(){
$('.grid').empty();
var cellsPer = prompt('How many cells would you like in a side?');
console.log('cellsPer = ' + cellsPer);
var cellWidth = (gridWidth / cellsPer) - 1;
console.log('cellSize = ' + cellWidth);
var cell = "<div class='cell'></div>";
for (var i = 0; i < cellsPer**2; i++) {
$('.grid').append(cell);
};
$('.cell').css({
'background':'blue','height': cellWidth+'px', 'width': cellWidth+'px',
'float':'left','margin': '0 1px 1px 0'
});
$('.cell').mouseenter(function() {
$(this).css('background','pink');
});
};
$(document).ready(function() {
fillGrid();
$('.grid').css({'width': gridWidth+'px'});
$('button').click(function(){
fillGrid();
});
});
button{
display:block;
margin:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Create New Grid</button>
<div class="grid"></div>
Move it outside $(document).ready function and add the mouse enter functionality as
' $(document).on('mouseenter','.cell',function() {
$(this).css('background','pink');
});'
Two issues I notice with this code
1) cellsPer ** 2 is not valid. Use Math.pow or cellsPer * cellsPer
2) You are only setting up the mouse enter listener on document.ready. Calling empty on your grid will remove all child elements - attached event listeners and all. This means you will need to re-add the event listeners every time you re-initialize the grid.
Here is an updated snippet with minimal changes to get your code working:
var gridWidth = 600;
var fillGrid = function(){
$('.grid').empty();
var cellsPer = prompt('How many cells would you like in a side?');
console.log('cellsPer = ' + cellsPer);
var cellWidth = (gridWidth / cellsPer) - 1;
console.log('cellSize = ' + cellWidth);
var cell = "<div class='cell'></div>";
for (var i = 0; i < cellsPer * cellsPer; i++) {
$('.grid').append(cell);
};
$('.cell').css({
'background':'blue','height': cellWidth+'px', 'width': cellWidth+'px',
'float':'left','margin': '0 1px 1px 0'
});
};
$(document).ready(function() {
fillGrid();
$('.grid').css({'width': gridWidth+'px'});
$('button').click(function(){
fillGrid();
$('.cell').mouseenter(function() {
$(this).css('background','pink');
});
});
$('.cell').mouseenter(function() {
$(this).css('background','pink');
});
});
button{
display:block;
margin:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Create New Grid</button>
<div class="grid"></div>
Since you're doing this for a class I'm not going to refactor the code but, one other suggestion I would make is adding the event listener in the fillGrid function, that way you neatly encapsulate everything that has to do with the grid in one place.

changing background image with a for loop

i have a table with 3 cells the middel 1 in a black image so it will look like there is a line in the middle of the screen.
now in the other cell i want to show pictures, so i tryed to do a loop that changing the images every second with by hiding the cells and then show them.
the script:
$(window).ready(function () {
//the images sits in a div with a hidden property.
var AlumniumPictures = $("#AlumnimPictureHolder").children();
var ShipozimPictures = $("#ShipozimPictureHolder").children();
//var timer = $.timer(yourfunction, 10000);
for (var i = 0; i < 10; i++) {
$(".almoniyomButtonTD").css({
"background-image": "url(" + $(AlumniumPictures[i]).attr('src') + ")"
});
$(".shipozimButtonTD").css({
"background-image": "url(" + $(ShipozimPictures[i]).attr('src') + ")"
});
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
//for some reson the code dosnt work if im not using the setInterval method.
document.setInterval(1000);
}
});
this is not working it only show me the first images and then stop.
is there a batter way to do this?
am im doing this right?
I think you might do this for the background:
$(window).ready(function () {
//the images sits in a div with a hidden property.
var AlumniumPictures = $("#AlumnimPictureHolder").children();
var ShipozimPictures = $("#ShipozimPictureHolder").children();
//var timer = $.timer(yourfunction, 10000);
time = 0;
step = 1000; // One secund
for (var i = 0; i < 10; i++) {
time+= step;
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
//for some reson the code dosnt work if im not using the setInterval method.
document.setInterval("changeBG('" + $(AlumniumPictures[i]).attr('src') + "', '.almoniyomButtonTD')", time);
document.setInterval("changeBG('" + $(AlumniumPictures[i]).attr('src') + "', '.shipozimButtonTD')", time);
}
});
function changeBG(image, obj) {
$(obj).css({
"background-image": "url(" + image + ")"
});
}
But I don't undestand what you want to do with this:
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
See the docs about setInterval. You need to tell it what code you are running.
window.setInterval(code, delay);
You aren't specifying any code for it to run! Try placing your for statement in a function and calling that.
Also, from Mozilla and MS docs setInterval seems to be on the window object, not on the document object. I don't think it will work the way you have it. I imagine if you looked in a debugger you would see an error thrown.
window.setInterval(myFunction, 1000);
function myFunction() {
for (var i = 0; i < 10; i++) {
$(".almoniyomButtonTD").css({
"background-image": "url(" + $(AlumniumPictures[i]).attr('src') + ")"
});
$(".shipozimButtonTD").css({
"background-image": "url(" + $(ShipozimPictures[i]).attr('src') + ")"
});
$(".almoniyomButtonTD").hide();
$(".shipozimButtonTD").hide();
$(".almoniyomButtonTD").show(1100);
$(".shipozimButtonTD").show(1100);
}
}

Categories