Selecting Multiple Elements height(); - javascript

I am just wondering why this jQuery won't work:
hdr = $('.header-wrapper, #top-bar, #new-showroom-header').height();
So as you can see I am trying to get the height of multiple elements and store them all within my variable. I'd expect jQuery to add all of the elements heights together to create a final value however when I console.log the variable hdr I get the height of the first element selected.
Any idea how I can select all and store them into my var?

Use $.each() to get total sum of height.
var hdr = 0;
$('.header-wrapper, #top-bar, #new-showroom-header').each(function () {
hdr += $(this).height();
});
FIDDLE DEMO

You can write a jQuery plugin for this scenario. :)
The following code below will return an array of heights based on the provided selectors.
[20,30,80]
jQuery Plugin
(function($) {
$.fn.heights = function() {
return this.map(function() {
return $(this).height();
}).toArray();
};
}(jQuery));
var heights = $('.header-wrapper, #top-bar, #new-showroom-header').heights();
document.body.innerHTML = JSON.stringify(heights); // [20,30,80]
body { font-family: monospace; white-space: pre; }
.header-wrapper { height: 20px; }
#top-bar { height: 30px; }
#new-showroom-header { height: 80px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="page-wrapper">
<div class="header-wrapper"></div>
<div id="top-bar"></div>
<div id="new-showroom-header"></div>
</div>
Alternatively, you could build a cache of heights along with their selectors.
{
"html>body>div>.header-wrapper": 20,
"html>body>div>#top-bar": 30,
"html>body>div>#new-showroom-header": 80
}
(function($) {
$.reduce = function(arr, fn, initVal) {
if (Array.prototype.reduce) { return Array.prototype.reduce.call(arr, fn, initVal); }
$.each(arr, function(i, val) { initVal = fn.call(null, initVal, val, i, arr); });
return initVal;
};
$.fn.heights = function() {
return $.reduce(this, function(map, el) {
map[$(el).fullSelector()] = $(el).height();
return map;
}, {});
};
$.fn.fullSelector = function() {
var sel = $(this)
.parents()
.map(function() { return this.tagName.toLowerCase(); })
.get()
.reverse()
.concat([this.nodeName])
.join(">");
var id = $(this).attr('id'); if (id) { sel += '#' + id; };
var cls = $(this).attr('class'); if (cls) { sel += '.' + $.trim(cls).replace(/\s/gi, '.'); };
return sel;
}
}(jQuery));
var heights = $('.header-wrapper, #top-bar, #new-showroom-header').heights();
document.body.innerHTML = JSON.stringify(heights, null, 2);
body { font-family: monospace; white-space: pre; }
.header-wrapper { height: 20px; }
#top-bar { height: 30px; }
#new-showroom-header { height: 80px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="page-wrapper">
<div class="header-wrapper"></div>
<div id="top-bar"></div>
<div id="new-showroom-header"></div>
</div>
Credit for the selector algorithm goes to Jesse Gavin.

No you can not get all element height using .height(); function
first you apply $.each() loop in collection then you can get height one by one
following code help you
$.each($('.header-wrapper, #top-bar, #new-showroom-header'),function(ind,item){
var Height = $(item).height();
});

Related

How to add to html article class variable from js

I have 6 styles in css and i want to use this code to apply them randomly:
<script>
function getRandom(max) {
return "style" + Math.floor(Math.random() * max);
}
document.getElementById('XXX').innerHTML = getRandom(6);
</script>
And I need to add XXX to article class
<article class="XXX">
This code doesn't work :(
First set a ID to the article tag
<article class="XXX" id="someId">
Then to set class to article use below code
var element = document.getElementById("someId");
element.className=getRandom(6);
Hope this helps!
//randomize plugin
(function($) {
$.rand = function(arg) {
if ($.isArray(arg)) {
return arg[$.rand(arg.length)];
} else if (typeof arg === "number") {
return Math.floor(Math.random() * arg);
} else {
return 4; // chosen by fair dice roll
}
};
})(jQuery);
//your list of classes
var items = ["class-1", "class-2", "class-3", "class-4", "class-5"];
//executes on page load
$("#addRandom").removeClass().addClass(jQuery.rand(items));
//button to inject random class
$("#randomize").click(function() {
var item = jQuery.rand(items);
$("#addRandom").removeClass().addClass(item);
});
#addRandom {
display:block;
width: 100px;
height: 100px;
margin: 10px
}
.class-1 {
background-color: purple;
}
.class-2 {
background-color: blue;
}
.class-3 {
background-color: green;
}
.class-4 {
background-color: yellow;
}
.class-5 {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="addRandom" class="">
</div>
<button id="randomize">randomize</button>
If you just need to add a CSS class to your element, the answer is plain easy:
document.getElementById("your-element").classList.add("your-class");
For more information, see classList.
Thanks to all! Here is a code that works as needed:
<script>
const elements = document.querySelectorAll('article');
elements.forEach(element => {
function getRandom(max) {
return "style" + Math.floor(Math.random() * max);
}
element.classList.add(getRandom(6));
});</script>

Combination filters + quick search with Isotope

I’m trying to combine two Isotope filtering features (combination filtering via checkbox and quick search) with no luck. My attempt is here: https://codepen.io/anon/pen/WJvmaj, which is a combination of both of the mentioned feature's demos.
At the moment the search is set to return searchResult and checkboxResult, the latter of which isn’t being defined properly in the code I can tell, and there lies my problem: I’m not sure what to set the checkboxResult variable to in order for it to target what’s being returned by the checkbox filtering.
Check if the element includes the text that input in search input or not with .includes() and if the element has any of selected class from checkboxs' value.
BTW, next time please provide a Minimal, Complete, and Verifiable example that demonstrates the problem, not a link to your fiddle or codepen, cause the links would be broken and other users couldn't understand what you asked and the scenario of the question.
$container.isotope({
filter: function() {
var $this = $(this)
var checkText = text == '' ? true : $this.text().includes(text)
var checkClass = inclusives.length == 0 ? true : false;
$.each(inclusives, function(index, c) {
var _class = $this.hasClass(c)
if (_class) {
checkClass = true;
return;
}
})
return checkText && checkClass
}
})
// quick search regex
var qsRegex;
var checkboxFilter;
// templating
var colors = ['red', 'green', 'blue', 'orange'];
var sizes = ['small', 'medium', 'large'];
var prices = [10, 20, 30];
createItems();
// init Isotope
var $container = $('#container')
var $output = $('#output');
// filter with selects and checkboxes
var $checkboxes = $('#form-ui input');
function createItems() {
var $items;
// loop over colors, sizes, prices
// create one item for each
for (var i = 0; i < colors.length; i++) {
for (var j = 0; j < sizes.length; j++) {
for (var k = 0; k < prices.length; k++) {
var color = colors[i];
var size = sizes[j];
var price = prices[k];
var $item = $('<div />', {
'class': 'item ' + color + ' ' + size + ' price' + price
});
$item.append('<p>' + size + '</p><p>$' + price + '</p>');
// add to items
$items = $items ? $items.add($item) : $item;
}
}
}
$items.appendTo($('#container'));
}
var $quicksearch = $('#quicksearch')
// debounce so filtering doesn't happen every millisecond
function debounce(fn, threshold) {
var timeout;
threshold = threshold || 100;
return function debounced() {
clearTimeout(timeout);
var args = arguments;
var _this = this;
function delayed() {
fn.apply(_this, args);
}
timeout = setTimeout(delayed, threshold);
};
}
function Filter() {
// map input values to an array
var inclusives = [];
// inclusive filters from checkboxes
$checkboxes.each(function(i, elem) {
// if checkbox, use value if checked
if (elem.checked) {
inclusives.push(elem.value);
}
});
// combine inclusive filters
var filterValue = inclusives.length ? inclusives.join(', ') : '*';
var text = $quicksearch.val()
$container.isotope({
filter: function() {
var $this = $(this)
var checkText = text == '' ? true : $this.text().includes(text)
var checkClass = inclusives.length == 0 ? true : false;
$.each(inclusives, function(index, c) {
var _class = $this.hasClass(c)
if (_class) {
checkClass = true;
return;
}
})
return checkText && checkClass
}
})
$output.text(filterValue);
}
$quicksearch.on('input', debounce(function() {
Filter()
}));
$checkboxes.change(function() {
Filter()
});
* {
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
.item {
width: 100px;
height: 100px;
float: left;
margin: 5px;
padding: 5px;
}
.item p {
margin: 0;
}
.red {
background: #F33;
}
.blue {
background: #88F;
}
.green {
background: #3A3;
}
.orange {
background: orange;
}
select,
label,
input {
font-size: 20px;
}
label {
margin-right: 10px;
}
#quicksearch {
height: 30px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//npmcdn.com/isotope-layout#3/dist/isotope.pkgd.js"></script>
<p><input type="text" id="quicksearch" placeholder="Search" /></p>
<div id="form-ui">
<p>
<label><input type="checkbox" value="red" /> red</label>
<label><input type="checkbox" value="green" /> green</label>
<label><input type="checkbox" value="blue" /> blue</label>
<label><input type="checkbox" value="orange" /> orange</label>
</p>
<p id="output">--</p>
</div>
<div id="container">
<!-- items added with JS -->
</div>

javascript appending span to text [duplicate]

This question already has answers here:
How to append text to a div element?
(12 answers)
Closed 5 years ago.
I'm currently trying to build my javascript function that gives css styles to every character in an element. Specifically, this function takes in an element, takes the text content in it, stores the text into an array and then create a bunch of spans to append to the text. Right now it seems like my code runs and when I check the variables in chrome dev tools, they return the correct values. However, when I actually implement this code, nothing changes visually but in the dev tools, I get my correct value of <span style="style i chose" > text </span>. Not sure what I did wrong here
var array = [];
var spanarray = [];
var words = document.getElementsByClassName("example")[0];
function fadeInByLetter () {
for(var i = 0; i < words.innerHTML.length;i++){
array.push(words.innerHTML[i]);
var span = document.createElement("span");
var textNode = document.createTextNode(array[i]);
span.appendChild(textNode);
var spancomplete = span;
spanarray.push(spancomplete);
}
for(var i = 0; i < array.length;i++){
spanarray[i].style.color = "red";
spanarray[i].style.background = "pink";
}
}
fadeInByLetter();
var array = [];
var spanarray = [];
var words = document.getElementsByClassName("example")[0];
function fadeInByLetter () {
for(var i = 0; i < words.innerHTML.length;i++){
array.push(words.innerHTML[i]);
var span = document.createElement("span");
var textNode = document.createTextNode(array[i]);
span.appendChild(textNode);
var spancomplete = span;
spanarray.push(spancomplete);
}
words.innerHTML="";
for(var i = 0; i < array.length;i++){
spanarray[i].style.color = "red";
spanarray[i].style.background = "pink";
words.appendChild(spanarray[i]);
}
}
fadeInByLetter();
The solution above should fix the problem. However you have some performance issues. You should save words.innerHTML in a string first. Then use the string instead of words.innerHTML.
That should do the trick:
function fadeInByLetter (wordsContainer) {
// extract text from the container and transform into array
var chars = wordsContainer.innerHTML.split('')
//clear the container
while (wordsContainer.firstChild) {
wordsContainer.removeChild(wordsContainer.firstChild);
}
for(var i = 0; i < chars.length;i++){
var span = document.createElement("span");
var textNode = document.createTextNode(chars[i]);
span.appendChild(textNode);
span.style.color = "red";
span.style.background = "pink";
// append new element
wordsContainer.appendChild(span)
}
}
fadeInByLetter(document.getElementsByClassName("example")[0]);
FYI: There is a library that does this same type of thing.
It's called lettering https://github.com/davatron5000/Lettering.js
Here is a demo using this library.
The library depends upon jQuery but there is also a version of this lib that uses plain javascript. See https://github.com/davatron5000/Lettering.js/wiki/More-Lettering.js
$(document).ready(function() {
$(".example").lettering();
});
//////////////// LETTERING SOURCE BELOW /////////////////////////////
//fadeInByLetter();
/*global jQuery */
/*!
* Lettering.JS 0.7.0
*
* Copyright 2010, Dave Rupert http://daverupert.com
* Released under the WTFPL license
* http://sam.zoy.org/wtfpl/
*
* Thanks to Paul Irish - http://paulirish.com - for the feedback.
*
* Date: Mon Sep 20 17:14:00 2010 -0600
*/
(function($) {
function injector(t, splitter, klass, after) {
var text = t.text(),
a = text.split(splitter),
inject = '';
if (a.length) {
$(a).each(function(i, item) {
inject += '<span class="' + klass + (i + 1) + '" aria-hidden="true">' + item + '</span>' + after;
});
t.attr('aria-label', text)
.empty()
.append(inject)
}
}
var methods = {
init: function() {
return this.each(function() {
injector($(this), '', 'char', '');
});
},
words: function() {
return this.each(function() {
injector($(this), ' ', 'word', ' ');
});
},
lines: function() {
return this.each(function() {
var r = "eefec303079ad17405c889e092e105b0";
// Because it's hard to split a <br/> tag consistently across browsers,
// (*ahem* IE *ahem*), we replace all <br/> instances with an md5 hash
// (of the word "split"). If you're trying to use this plugin on that
// md5 hash string, it will fail because you're being ridiculous.
injector($(this).children("br").replaceWith(r).end(), r, 'line', '');
});
}
};
$.fn.lettering = function(method) {
// Method calling logic
if (method && methods[method]) {
return methods[method].apply(this, [].slice.call(arguments, 1));
} else if (method === 'letters' || !method) {
return methods.init.apply(this, [].slice.call(arguments, 0)); // always pass an array
}
$.error('Method ' + method + ' does not exist on jQuery.lettering');
return this;
};
})(jQuery);
span {
font-size: 74px;
font-family: Arial;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 11px;
display: inline-block;
}
.char1 {
color: red;
transform: rotateZ(-10deg);
}
.char2 {
color: blue;
transform: rotateZ(-12deg);
}
.char3 {
color: purple;
transform: rotateZ(12deg);
}
.char4 {
color: pink;
transform: rotateZ(-22deg);
}
.char5 {
color: yellow;
transform: rotateZ(-12deg);
}
.char6 {
color: gray;
transform: rotateZ(22deg);
}
.char7 {
color: orange;
transform: rotateZ(10deg);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span class="example">Example</span>

Javascript/jQuery parse inline style as each object

I want to be able to parse inline css and have it as object in key pairs. Something like:
<div background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
{
backgroundImage : "http://domain.com/images/image.jpg",
backgroundSize: "cover",
padding: "100px 0"
}
This function works great for the most of the part. I'm having problem with background-image
it strips it completely and I end up with "url(http" instead.
function parseCss(el) {
var output = {};
if (!el || !el.attr('style')) {
return output;
}
var camelize = function camelize(str) {
return str.replace(/(?:^|[-])(\w)/g, function(a, c) {
c = a.substr(0, 1) === '-' ? c.toUpperCase() : c;
return c ? c : '';
});
}
var style = el.attr('style').split(';');
for (var i = 0; i < style.length; ++i) {
var rule = style[i].trim();
if (rule) {
var ruleParts = rule.split(':');
var key = camelize(ruleParts[0].trim());
output[key] = ruleParts[1].trim();
}
}
return output;
}
I'm pretty sure that "replace" function needs to be modified to make it work with image url
You might be able to do something like this, it would still fail for some edge cases with content. It is not running your camel case, but that is simple enough to call.
var x = document.getElementById("x");
var str = x.getAttribute("style"); //x.style.cssText;
console.log(str);
var rules = str.split(/\s*;\s*/g).reduce( function (details, val) {
if (val) {
var parts = val.match(/^([^:]+)\s*:\s*(.+)/);
details[parts[1]] = parts[2];
}
return details;
}, {});
console.log(rules);
div {
font-family: Arial;
}
<div style="color: red; background: yellow; background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;" id="x">test</div>
Instead of reading the the style attribute, you could iterate over the style properties. This way you avoid the problems with delimiters that are embedded in style values:
function parseCss(el) {
function camelize(key) {
return key.replace(/\-./g, function (m) {
return m[1].toUpperCase();
});
}
var output = {};
for (var a of el.style) {
output[camelize(a)] = el.style[a];
}
return output;
}
// Demo
var css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>
This does expand some consolidated styles you can have in the style attribute, such as padding, which splits into paddingLeft, paddingRight, ...etc.
With the use of some more ES6 features the above can be condensed to:
function parseCss(el) {
let camelize = key => key.replace(/\-./g, m => m[1].toUpperCase());
return Object.assign(
...Array.from(el.style, key => ({[camelize(key)]: el.style[key]})));
}
// Demo
let css = parseCss(document.querySelector('div'));
console.log(css);
<div style="background-image: url('http://domain.com/images/image.jpg');background-size: cover;padding: 100px 0;">
</div>
You can try with this, tested on few examples:
styleObj={};
style=$('div').attr('style');
rules=style.split(';');
rules = rules.filter(function(x){
return (x !== (undefined || ''));
}); // https://solidfoundationwebdev.com/blog/posts/remove-empty-elements-from-an-array-with-javascript
for (i=0;i<rules.length;i++) {
rules_arr=rules[i].split(/:(?!\/\/)/g); // split by : if not followed by //
rules_arr[1]=$.trim(rules_arr[1]).replace('url(','').replace(')','');
if(rules_arr[0].indexOf('-')>=0) {
rule=rules_arr[0].split('-');
rule=rule[0]+rule[1].charAt(0).toUpperCase()+rule[1].slice(1);
}
else {
rule=rules_arr[0];
}
styleObj[$.trim(rule)]=rules_arr[1];
}
console.log(styleObj);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div style="font-size: x-large; color: #ff9900; background-image: url('http://placehold.it/100x100');">Using inline style sheets - or is that inline styles?</div>
Demo (easier for testing of different inline styles): https://jsfiddle.net/n0n4zt3f/2/
P.S. Trimming and camel case are left... can be added, of course...

Why isn't it possible to change max-height with % in javascript?

I'm trying to build a responsive menu, with a hamburger icon. I want the menu list to slide in and out, no jquery - pure javascript only.
HTML :
<div id="animation">
</div>
<button id="toggle">Toggle</button>
CSS :
div {
width: 300px;
height: 300px;
background-color: blue;
}
Javascript :
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback){
var inter = -1, start = 100, end = 0;
if(type==true){
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function(){
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if(start == end){
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function(){
animate(hidden, function(){
hidden = (hidden == false) ? true : false;
});
}
div.style.maxHeight = "50%";
The problem is that proportional height in an element needs a fixed height on the parent, and you didn't provided any parent with a fixed height because for the maxHeight property too the % Defines the maximum height in % of the parent element.
You have to put your div in a parent container with a fixed height, this is your working code:
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback) {
var inter = -1,
start = 100,
end = 0;
if (type) {
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function() {
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function() {
animate(hidden, function() {
hidden = !hidden ;
});
}
div.style.maxHeight = "50%";
#animation {
width: 300px;
height: 300px;
background-color: blue;
}
#parent {
width: 500px;
height: 500px;
}
<div id="parent">
<div id="animation">
</div>
<button id="toggle">Toggle</button>
</div>
Note:
As stated in comments there are some statements in your JavaScript code that need to be adjusted:
if(type==true) can be written as if(type).
hidden = (hidden == false) ? true : false; can be shortened to hidden = !hidden
There seems to be a few errors with your code. I have fixed the js and added comments to what I have changed
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function (type, callback) {
var start = 100,
end = 0;
if (type) {
start = 0;
end = 100;
}
var si = setInterval(function () {
if (type) { // check whether to open or close animation
start++;
} else {
start--
}
div.style.maxHeight = start + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
callback.call(this); // do the callback function
}
var hidden = false;
but.onclick = function () {
animate(hidden, function () {
hidden = !hidden; // set hidden to opposite
});
}
/*make sure parent container has a height set or max height won't work*/
html, body {
height:100%;
margin:0;
padding:0;
}
div {
width: 300px;
height: 300px;
background-color: blue;
}
<div id="animation"></div>
<button id="toggle">Toggle</button>
Example Fiddle

Categories