I am still new to Javascript and JQuery. I have written a small function I run from document-ready. Its purpose is to set the height of a div as a multiple of line-heights:
function setLoginLinksHeight(numOfLines) {
var ll = hash(LOGIN_LINKS);
$(ll).css('line-height','130%');
var lh = $(ll).css('line-height');
var nh = lh * numOfLines; // Issue here
$(ll).height(nh);
}
From FireBug, the line-height I retrieve is 15.5833px. When I multiply it by 2 (for example), nh is set to NaN. I saw in this question that the retrieved value can have any format (%, px, etc...). This is scary!
How can I convert the returned value into a number of pixels without units into order to be able to create multiples of it? Is there a library/function available for this in Javascript or JQuery? What is the recommended practice in this case? Thanks.
EDIT
I have developed a small unit splitter following mblase75's solution:
function splitUnit(e) {
var eUnit = '';
var eValue;
if( e && ( length = e.search( /px/ ) ) ) {
eUnit = 'px';
eValue = e.substr( 0, length );
} else if ( e && ( length = e.search( /em/ ) ) ) {
eUnit = 'em';
eValue = e.substr( 0, length );
} else {
eValue = e;
}
return new Array( eValue, eUnit );
}
Change to:
var lh = parseFloat($(ll).css('line-height'));
Of course, this doesn't guarantee that you'll be getting a number of pixels, just that you'll be getting a number. To extract the units separately, add:
var lhunits = $(ll).css('line-height').match(/\D+$/)[0];
// gets first element of array
...and then combine the calculation with the old units:
var nh = (lh*numOfLines) + lhunits;
var test = "15.83333px";
alert(parseFloat(test));
Just tried this in jsFiddle. Worked as expected and returned the value without pixels
Related
Goal
I'm trying to limit the height of each Award Category to the total height of 3 award divs. The reason for this is that it is dynamic and the height may vary depending on what the user puts in for the award info.
Link to CodePen for more context: https://codepen.io/Kaleshe/pen/QWpdJQq
Problem
For some reason, only the first element is being registered and I can't put my finger on why.
According to the error the next item in the loop is undefined, but it is picked up if I console log it outside of the loop like this awardCatContainers[0].querySelectorAll('.award')
Code
const awardCatContainers = document.querySelectorAll( '.award-category-container' );
const button = document.querySelector( '.award .button' );
awardCatContainers.forEach( (container) => {
let awards = container.querySelectorAll( '.award' );
let height = getContainerHeight(awards);
container.style.maxHeight = height + 'px';
});
function getContainerHeight(containerChildren) {
let height = 0;
for ( let a = 0; a <= 3; a++ ) {
height += containerChildren[a].offsetHeight;
}
return height;
}
Edit/Resolution
After looking at the solution provided by H. Udara I was able to confirm that my method worked. Leading me to do further debugging.
I then realised that the error was due to there not being a check for if a category has 3 or less awards. After adding in this check and a const to specify the max elements each category should show, the code now works.
const containers = document.querySelectorAll( '.award-category-container' );
const maxElems = 4;
for ( let c = 0; c < containers.length; c++) {
let awards = containers[c].querySelectorAll( '.award' );
if ( awards.length >= maxElems ) {
let height = setContainerHeight(awards);
containers[c].style.maxHeight = height + 'px';
}
}
// Takes an array of children and uses the total offsetHeight of the first 3 elements to create a height
function setContainerHeight(containerChildren) {
let height = 0;
for ( let a = 0; a < maxElems; a++ ) {
height += containerChildren[a].offsetHeight;
}
return height;
}
The querySelector returns a static NodeList. So when this code is run, probably only one element is rendered in the page. What you can try doing is adding a timeout to this code. This will help you debug the issue.
But do not make this your final code. Because you can never be certain of the timeout period. If the network is too slow it could take well over 3 seconds to load the elements. Look into promises or callbacks and implement your final code. If you are making AJAX calls to get data before creating the elements, use the callback provided by AJAX to determine if the AJAX call is complete.
const awardCatContainers = document.querySelectorAll( '.award-category-container' );
const button = document.querySelector( '.award .button' );
// set a timeout
setTimeout(() => {awardCatContainers.forEach( (container) => {
let awards = container.querySelectorAll( '.award' );
let height = getContainerHeight(awards);
container.style.maxHeight = height + 'px';
})}, 3000);
function getContainerHeight(containerChildren) {
let height = 0;
for ( let a = 0; a <= 3; a++ ) {
height += containerChildren[a].offsetHeight;
}
return height;
}
You need to loop the awards and apply the styling:
awardCatContainers.forEach( (container) => {
let awards = container.querySelectorAll( '.award' );
let height = getContainerHeight(awards);
//container.style.maxHeight = height + 'px';
for (let award of awards) award.style.maxHeight = height + 'px';
});
It's possible that I misunderstood your problem, in which case you will need to provide more information.
getContainerHeight is also strange, you go from 0 to 3. It would help a lot in understanding your exact intention if I knew what your structure is.
I'm trying to figure out what will be the JavaScript formula if I have a data in my database and this is i want to be the output:
if the data = 10 I want to be output that in a 100% in which I will be going to use in an div element height
if the data = 65 I want to be output that in a 0% in which I will be going to use in an div element height
and this is my code right now but I can't figure it out:
var datas = JSON.parse(data);
var ID, Bio, Non_Bio, Recy, Extra;
var div = 10;
ID = datas[0].ID;
Bio = datas[0].Bio;
Non_Bio = datas[0].Non_Bio;
Recy = datas[0].Recy;
Extra = datas[0]. Extra;
var obtained = Bio;
var obtained2 = Non_Bio;
var obtained3 = Recy;
var obt = obtained*100/div;
var obt2 = obtained2*100/div;
var obt3 = obtained3*100/div;
var water1 = $("#water1").height() + obt;
var water2 = $("#water2").height() + obt2;
var water3 = $("#water3").height() + obt3;
If the math can't be solved in one's head, doing it on paper can help, particularly when solving a pair of simultaneous equations using high school maths.
Assuming the ultrasound value to height relationship is linear you can write it as the equation of a line:
h = a * u + b ... 1)
where h is height, u is the ultrasound sensor reading, and a and b are constants.
Now take two calibration values of sensor readings taken for an empty and a full bin and call them c0 and c100 respectively.
From 1)
0 = a * c0 + b ... 2) using the c0 value , and
100 = a * c100 + b ... 3) using c100
Solving this pair of simultaneous equations proceeds along the lines of
b = 0 -a*c0 ... from 2)
b = 100 -a*c100 ... 4) from 3)
Hence
0 -a*c0 = 100 -a*c100
a*c100 - a*c0 = 100
a = 100/(c100-c0) ... 5)
and now substituting 4) back into 2) gives
b = 100 - a*c100 ... 6)
In this test example, the equations are converted into a factory function that returns an object with calibrate and height functions calibrate(c0, c100) and height( sensor). The height returned is rounded to the nearest quarter due to an overall lack of precision in the data.
function createBin() {
var a, b;
function calibrate( c0, c100) {
a = 100/(c100-c0);
b = 100 - a*c100;
}
function height( sensor) {
let h = a * sensor + b;
return Math.round( 4*h)/4;
}
return {calibrate, height};
}
const bin = createBin();
bin.calibrate (65, 10);
var readings = [67, 65, 37, 10, 5];
readings.forEach(
reading => console.log( "height( %s) = %s%", reading, bin.height(reading))
);
Note that when dealing with real world sensors, calibration data can vary between sensors and installations - hard coding equations that need to be calibrated against hardware variability is something to be avoided.
var datas=[{
ID :10,
Bio :7,
Non_Bio: 65,
Recy :75,
Extra :20
}]
var obt=[];
datas.map((data,index)=>{
console.log(data)
Object.values(data).map(item=>{
console.log(item)
if(item===10){
obt.push("100%");
}
else{
obt.push("0%");
}
})})
console.log("required output:");
console.log(obt);
Assumed: ID = datas[0].ID; since you are fetching from array 0th index and then its key.It mus be array of object (you have not given the proper inputs.) and the if logic can be changed accordingly as you mentioned if its 10 it must be 100%.
Logic: Just iterating each object of the array and then getting the object values (of each key i.e. id,bio etc..) and checking the value if divisible by 10 then pushing that data into empty array so you can use it further. You can also insert the output data into map.
I'm having a weird issue in JS comparing strings. One string is from a user input.
y = data;
document.getElementById("typeThisWord").innerHTML = y;
x = document.getElementById("inputField");
document.getElementById("youTyped").innerHTML = x.value;
first = document.getElementById("youTyped");
second = document.getElementById("typeThisWord");
if(first==second) correct=true;
When the words are the same, it still comes out false. I added in the 'first' and 'second' variables just to see if it would make a difference. Previously I've tried just comparing 'x' to 'y'. I've also tried x.value==y, x==y.value, and x.value==y.value. THe same with 'first' and 'second.' Surprisingly first.value==second.value came out to be true all the time, even when it shouldn't be.
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var x, y;
var first, second;
var availV = window.innerHeight - 100;
var availH = window.innerWidth - 100;
var randV, randH;
var correct = new Boolean(); correct=true;
var imageX;
function displayWord() {
if(correct) {
correct=false;
$.ajax({
url: "http://localhost:25578/TypeGood/VisitsSession",
success: function(data) { y = data; },
async: false
});
document.getElementById("typeThisWord").innerHTML = y;
imageX = document.createElement("img");
imageX.src = "https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRPRV4XdE7C9sa0pM-FeXcOSQydg7Sh0INg-ZD6FKZ4wjY8WPHa5Q";
imageX.height = 100;
imageX.width = 100;
imageX.style.position = "absolute";
randV = Math.round( Math.random() * availV );
randH = Math.round( Math.random() * availH );
imageX.style.top = randV + "px";
imageX.style.left = randH + "px";
imageX.style.zIndex = "-20";
document.body.appendChild(imageX);
}
x = document.getElementById("inputField");
document.getElementById("youTyped").innerHTML = x.value;
first = document.getElementById("youTyped").innerHTML;
second = document.getElementById("typeThisWord").innerHTML;
if(first==second) {correct=true;}
x.value = "";
}
</script>
getElementById returns a reference to a DOM element, not a string, so you're not comparing strings, you're comparing DOM elements. Since they're different elements, they aren't ==.
At a minimum, your last three lines should be something like:
first = document.getElementById("youTyped").innerHTML;
second = document.getElementById("typeThisWord").innerHTML;
if(first==second) correct=true;
(E.g., using the innerHTML of the elements, which is a string.) Although I think I'd probably keep the values around in variables rather than going back to the DOM for them.
For Example:
y = data; //data is string value "First"
Change this value to new string "first" >> here f is small
y2 = "first"
Now, When both are of same type, its case sensitive.
if(y==y2)
so values are..
First == first
that will be false.
So make sure of data you are passing in inner html. and make sure you are not adding some white space to it..
I hope this may solve problem. :)
comment back if not solved after modifying the code :)
use this instead of (first==second):
if(first===second)
and retrieve value from html like this:
first = document.getElementById("youTyped").innerHTML;
I am trying to make a script to pick random number between two numbers . but it picks same number sometimes. i donot want to repeat same number until array is finished .
Here is my code
$(document).ready(function () {
abc();
test = array();
function abc() {
res = randomXToY(1, 10, 0);
$('#img' + res).fadeTo(1200, 1);
//$(this).addClass('activeImg');
//});
setTimeout(function () {
removeClassImg(res)
}, 3000);
}
function removeClassImg(res) {
$('#img' + res).fadeTo(1200, 0.1);
//$('#img' + res).removeClass('activeImg');
abc();
}
function randomXToY(minVal, maxVal, floatVal) {
var randVal = minVal + (Math.random() * (maxVal - minVal));
return typeof floatVal == 'undefined' ? Math.round(randVal) : randVal.toFixed(floatVal);
}
});
Does Anybody have idea about this ...
You'll have to maintain a list of numbers that have already been generated, and check against this list. Re-generate a new number if you find a dupe.
If you do not want the random numbers repeating themselves you have to keep track of the some way.
If you have the range you are dealing with is relatively small, you can create an array with all possible results and simply randomly pick out of it.
function Randomizer(minVal, maxVal, floatVal){
var possible_results = []; // for larger arrays you can build this using a loop of course
var randomization_array = [];
var count = minVal;
var incrementor = floatVal || 1; // set the distance between possible values (if floatVal equals 0 we round to 1)
while (count <= maxVal) {
possible_results.push(count);
count += incrementor;
}
this.run = function(){
// if randomization_array is empty set posssible results into it
randomization_array = randomization_array.length ? randomization_array : $.merge(randomization_array, possible_results);
// pick a random element within the array
var rand = Math.floor(Math.random()*randomization_array.length);
// return the relevant element
return randomization_array.splice(rand,1)[0];
}
}
and in order to use it (it creates a specialized object for each possible range):
rand = new Randomizer(1,10,0);
rand.run();
note that this approach does not work well for very large ranges
Is there a simple way to find the min/max property from an array of elements in jQuery?
I constantly find myself dynamically resizing groups of elements based on the minimum and maximum counterparts. Most of the time this pertains to the width and/or height of an element but I'm sure this could be applied to any property of an element.
I usually do something like this:
var maxWidth = 0;
$('img').each(function(index){
if ($(this).width() > maxWidth)
{
maxWidth = $(this).width();
}
});
But it seems like you should be able to do something like this:
var maxWidth = $('img').max('width');
Does this functionality exist in jQuery or can someone explain how to create a basic plugin that does this?
Thanks!
Use Fast JavaScript Max/Min - John Resig
Example with three logos of google, yahoo and bing.
HTML
<img src="http://www.google.co.in/intl/en_com/images/srpr/logo1w.png" alt="Google Logo" /><br/>
<img src="http://l.yimg.com/a/i/ww/met/yahoo_logo_in_061509.png" alt="Yahoo Logo" /><br/>
<img src="http://www.bing.com/fd/s/a/h1.png" alt="Bing Logo" />
Javascript
$(document).ready(function(){
// Function to get the Max value in Array
Array.max = function( array ){
return Math.max.apply( Math, array );
};
// Function to get the Min value in Array
Array.min = function( array ){
return Math.min.apply( Math, array );
};
//updated as per Sime Vidas comment.
var widths= $('img').map(function() {
return $(this).width();
}).get();
alert("Max Width: " + Array.max(widths));
alert("Min Width: " + Array.min(widths));
});
P.S: jsfiddle here
You can use apply outside the context of OO, no need to extend the prototype:
var maxHeight = Math.max.apply( null,
$('img').map(function(){ return $(this).height(); }).get() );
I like the elegant solution posted as a .map() example in the jQuery docs on how to equalize div heights. I basically adapted it to work with widths and made a demo.
$.fn.limitWidth = function(max){
var limit = (max) ? 'max' : 'min';
return this.width( Math[limit].apply(this, $(this).map(function(i,e){
return $(e).width();
}).get() ) );
};
// Use the function above as follows
$('.max-width').limitWidth(true); // true flag means set to max
$('.min-width').limitWidth(); // no flag/false flag means set to min
Take a look at the calculation plugin, maybe it can help you with your problems.
They offer a number of math functions, like min, max and avg on DOM-elements.
Examples:
$("input[name^='min']").min();
$("input[name^='max']").max();
Rolled up as a plugin to return min-max of width and height:
// Functions to get the Min & Max value in Array
if (!Array.min) { Array.min = function( array ){return Math.min.apply( Math, array )} }
if (!Array.max) { Array.max = function( array ){return Math.max.apply( Math, array )} }
(function( $ ){ // Standard jQuery closure to hide '$' from other libraries.
// jQuery plug-in to get the min and max widths of a set of elements
$.fn.dimensionsMinMax = function(whnx) {
/*
################################################################################
Name
====
dimensionsMinMax(whnx) - jQuery plug-in to get min & max width & height
Parameters
==========
whnx - A 4-element array to receive the min and max values of the elements:
whnx[0] = minimum width;
whnx[1] = maximum width;
whnx[2] = minimum height;
whnx[3] = maximum height.
Returns
=======
this - so it can be "chained".
Example
=======
var minmax = new Array(4);
var number_of_images = $('img').dimensionsMinMax(minmax).class('abc').length;
console.log('number of images = ', number_of_images);
console.log('width range = ', minmax[0], ' to ', minmax[1]);
console.log('height range = ', minmax[2], ' to ', minmax[3]);
################################################################################
*/
var widths = new Array(this.length);
var heights = new Array(this.length);
this.each(function(i){
$this = $(this);
widths[i] = $this.width();
heights[i] = $this.height();
});
whnx[0] = Array.min( widths);
whnx[1] = Array.max( widths);
whnx[2] = Array.min(heights);
whnx[3] = Array.max(heights);
return this;
}
})( jQuery ); // End of standard jQuery closure.
I wrote a simple plugin to do exactly this - see gregbrown.co.nz/code/jquery-aggregate . With it installed, you could do:
var maxWidth = $('img').aggregate('width', 'max');
You can use native "sort" function to have more control over which elements are compared
Array.prototype.deepMax = function(comparator){
if(typeof comparator === 'function'){
var sorted = this.slice(0).sort(comparator);
return sorted[sort.length - 1];
}
return Math.max.apply(Math, this);
};
and you can call it like
var maxWidth = $('img').deepMax(function(a, b){
//-1 if a < b; +1 otherwise
return $(a).width() - $(b).width();
});
OR
you can use _.max of Underscore which is can be implemented like...
Array.prototype.max = function(iterator){
if(!iterator && obj[0] === +obj[0])
return Math.max.apply(Math, this);
var result = -Infinity, lastComputed = -Infinity;
this.forEach(function(value, index){
var computed = iterator ? iterator(value, index, this) : value;
computed > lastComputed && (result = value, lastComputed = computed);
});
return result;
};
var maxWidth = $('img').max(function(val){ return $(val).width();});
The Plugins/Authoring page actually has an example for determining the tallest element.
It's basically what you have here, just rolled into a plugin for easy access. Maybe you could appropriate it for your uses.