Javascript get element class or data attributes - javascript

At the moment I have a javascript function which looks for an id and changes some CSS. However I want this function to run on multiple divs. Therefore I need my function to look for a class or a data attribute. Please can you help me!
<script>
var div = document.getElementById('hover')
div.onclick = function () {
this.style.width = '800px'
this.style.transition = 'all 1s'
this.style.backgroundColor = 'red'
}
</script>

You could wrap all your elements inside a common parent, then you apply your click event handler to that parent, checking the target that originated the event.
Doing so you need to attach the event just to a single element (and not to every single element).
Also, your style should be declared in the CSS as a class, so you only need to switch that specific class (and it's always better to keep off css from javascript, for the mantainability)
here is a simple example http://codepen.io/anon/pen/jPwXVr
CSS
.open {
width: 800px;
-webkit-transition : all 1s;
-moz-transition : all 1s;
transition : all 1s;
background: red;
}
JS
document.getElementById('wrap').addEventListener('click', function(ev) {
var target = ev.target
if (target.nodeName === 'DIV') {
target.className = 'open';
}
}, false);
if the structure of your markup makes impossibile to use a common wrapper you could attach the event on the body element, like so
http://codepen.io/anon/pen/aOwPWY?editors=011
CSS
.element {
width: 800px;
-webkit-transition : all 1s;
-moz-transition : all 1s;
transition : all 1s;
}
.element.open {
background: red;
}
JS
document.body.addEventListener('click', function(ev) {
var t = ev.target;
/* I used classList for the sake of brevity, check caniuse.com
for its support across browser */
if (t.classList.contains('element')) {
t.classList.toggle('open');
}
}, false);

You need to use a class, which is better. And loop it through!
<script>
var divs = document.getElementsByClassName('hover');
for (var i = 0; i < divs.length; i++)
divs[i].onclick = function () {
this.style.width = '800px'
this.style.transition = 'all 1s'
this.style.backgroundColor = 'red'
}
</script>
Example using addEventListener:
<script>
var divs = document.getElementsByClassName('hover');
for (var i = 0; i < divs.length; i++)
divs[i].addEventListener("click", function () {
this.style.width = '800px'
this.style.transition = 'all 1s'
this.style.backgroundColor = 'red'
}, false);
</script>

Related

Fading in iframe using JavaScript

I am trying to fade in my iframe smoothly with JavaScript. I have seen links online and most of the answers were related to jQuery. Why must I use jQuery for a simple fading? Can anyone explain?
Also I do not mind using JQuery, after all its a part of javascript. I am just looking for a simple solution. Since I am using the below fadeIn() function, does jQuery perform better than the below function?
<iframe id="iframe" style="
position: fixed;
opacity: 0;
height: 100%;
width: 100%;
overflow: hidden;
z-index: 10;
display: none;
">
</iframe>
<script>
//Creation of button before this code
button_01.onPointerUpObservable.add(function () {
let iframe = document.getElementById("iframe");
iframe.src = "LINK";
fadeIn(iframe, 2000);
iframe.style.display = 'Block';
});
function fadeIn(el, duration) {
/*
* #param el - The element to be faded out.
* #param duration - Animation duration in milliseconds.
*/
var step = 10 / duration;
var opacity = 0;
function next() {
if (opacity >= 1) { return; }
el.style.opacity = (opacity += step);
setTimeout(next, 10);
}
next();
}
</script>
Some people suggest jQuery because there's a function called x.fadeIn(300) which causes it to animate pretty nicely, you don't actually need this and it can be accomplished by adding a class or using vanilla animations and removing it later
Both:
Option 1: Class
.shown {
opacity: 1;
}
iframe {
transition: .3s opacity;
}
iframe.classList.add('shown');
Option 2: JS only
iframe.style.transition = '.3s';
iframe.style.opacity = '1';
// remove it after it's done
setTimeout(() => {
iframe.style.transition = '';
}, 300);

How to replicate jquery animation sequence in vanilla js/css

As the title says, I would like to replicate the animation bellow. the jquery API https://api.jquery.com/toggle/ decibels this default behavior as so:
easing (default: swing)
Type: String
A string indicating which easing function to use for the transition.
but I don't understand how the transition works. I have tried changing the opacity, translating the element, ect, but obviously no luck. If it is impossible to do this in a simple way without jquery, an answer for the transition effect without the toggle function is also acceptable (but not hide() and show() as I have already tried those and couldn't get it to work properly). And yes, I would prefer a swing transition if possible. any help is appreciated.
document.addEventListener('click', ()=>{
$('#elem').toggle('.hide');
});
.hide{
display:none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='elem' class= 'hide'>
easing text transion
</div>
I don´t know if I understood your question correctly but you want
document.addEventListener('click', ()=>{
$('#elem').toggle('.hide');
});
in normal JS?
You have two options: set an data attribute to #elem or you check if #elem has the class
.hide. But its easier to just add the css to the element
With data attribute:
<div id='elem' data-status='inv' class='hide'>
easing text transion
</div>
let toggleFunction = function() {
let elem = document.querySelector('#elem');
if (elem.dataset.status == "inv") {
elem.className = "";
elem.dataset.status = "vis";
} else if (elem.dataset.status == "vis") {
elem.className = "hide";
elem.dataset.status = "inv";
}
}
document.addEventListener('click', toggleFunction);
Or with css:
<div id='elem' style='display: none;'>
easing text transion
</div>
let toggleFunction = function() {
let elem = document.querySelector('#elem');
if (elem.style.display == 'none') {
elem.style.display = 'inherit';
} else {
elem.style.display = 'none';
}
}
document.addEventListener('click', toggleFunction);
If you still want the animation:
<div id='elem' style='height: 0px;'>
easing text transion
</div>
#elem {
transition: 1s ease-in-out all;
overflow-y: hidden;
}
let toggleFunction = function() {
let elem = document.querySelector('#elem');
if (elem.style.height == '0px') {
elem.style.height = '18px';
} else {
elem.style.height = '0px';
}
}
document.addEventListener('click', toggleFunction);
I hope I could help
You can toggle a class and use a css transition to do it
document.addEventListener('click', () => {
document.getElementById('elem').classList.toggle('no-height')
})
#elem {
max-height: 2em;
transition: max-height 0.5s ease-in-out;
overflow-y: hidden;
}
#elem.no-height {
max-height: 0;
}
<div id='elem'>
easing text transion
</div>

Set display none after transition has finished with pure JS

How would I set display to none (and vice versa) only after the CSS transition has finished?
This is my current code but it doesn't work nicely – the transition isn't visible because I'm adding/removing display:none; straightaway.
<script type="text/javascript">
var mobile_menu = document.querySelector('#mobile-menu');
var mobile_menu_open = document.querySelector('#open-mobile-menu');
var mobile_menu_close = document.querySelector('#close-mobile-menu');
mobile_menu_open.addEventListener('click', function (event) {
mobile_menu.classList.remove('duration-100', 'ease-in', 'opacity-0', 'scale-95');
mobile_menu.classList.add('duration-200', 'ease-out', 'opacity-100', 'scale-100');
mobile_menu.removeAttribute('style');
});
mobile_menu_close.addEventListener('click', function (event) {
mobile_menu.classList.remove('duration-200', 'ease-out', 'opacity-100', 'scale-100');
mobile_menu.classList.add('duration-100', 'ease-in', 'opacity-0', 'scale-95');
mobile_menu.style.display = "none";
});
</script>
I can only think of setTimeout(); but in most cases it's not considered a proper solution but rather a dirty hack. Do I have any other options here?
You can use the transitionend event listener.
mobileMenu.addEventListener('transitionend', setDisplayNone);
After the animation is finished, it will execute setDisplayNone(). If you only want to run this once, you can add this at the end of the setDisplayNone function:
mobileMenu.removeEventListener('transitionend', setDisplayNone);
Example:
var div = document.querySelector('div')
function setDisplayNone() {
div.style.display = 'none'
}
document.querySelector('button').onclick = function() {
div.addEventListener('transitionend', setDisplayNone);
div.classList.add('transition')
}
.transition {
transition-duration: 3s;
opacity: 0;
}
<button>Click me!</button>
<br>
<div id='someDiv'>
Click the button!
</div>
This text will shift upwards once the div has display:none

add className on scroll in JavaScript

I'm trying to add a className on scroll. I keep getting a
document is undefined
edit: I found out I was getting the error from the typo. When I define document.getElementsByClassName("main-nav").scrollTop nothing comes up in the console. As well as the page does not get affected.
window.onscroll = function() {
windowScroll();
};
function windowScroll() {
if (document.getElementsByClassName("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.getElementsByClassName("main-nav").className = "test";
} else {
document.getElementsByClassName("main-nav").className = "";
}
}
CSS is
.test {
background: pink
}
I'm not necessarily looking for the answer, I just want guidance
There are 2 problems:
getElementsByClassName returns an array of HTMLCollection and it has no property scrollTop. You probably want the first item so the code shoul be document.getElementsByClassName("main-nav")[0] (or document.querySelector(".main-nav"))
But if you try it, you will get an error:
Cannot read property 'scrollTop' of undefined
window.onscroll = function() {
windowScroll();
};
function windowScroll() {
if (document.getElementsByClassName("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.getElementsByClassName("main-nav").className = "test";
} else {
document.getElementsByClassName("main-nav").className = "";
}
}
html, body {
height: 150%;
}
.test {
background: pink
}
<div class="main-nav"></div>
The reason is that you override the class attribute of .main-nav by this assignment:
document.getElementsByClassName("main-nav").className = "";
In this line you set the class attribute to empty string. You probably want to add / remove the test call but keeping the main-nav class.
There are 2 things you can do:
Set the id attribute to main-nav instead of the class attribute, then use document.getElementById method.
window.onscroll = function() {
windowScroll();
};
function windowScroll() {
if (document.getElementById("main-nav").scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.getElementById("main-nav").className = "test";
} else {
document.getElementById("main-nav").className = "";
}
}
html, body {
height: 150%;
}
#main-nav {
position: fixed;
width: 100%;
}
.test {
background: pink
}
<div id="main-nav">Main Nav</div>
Toggle only the test class using classList.toggle.
window.onscroll = function() {
windowScroll();
};
function windowScroll() {
if (document.getElementsByClassName("main-nav")[0].scrollTop > 50 || document.documentElement.scrollTop > 50) {
document.getElementsByClassName("main-nav")[0].classList.add("test");
} else {
document.getElementsByClassName("main-nav")[0].classList.remove("test");
}
}
html, body {
height: 150%;
}
.main-nav {
position: fixed;
width: 100%;
}
.test {
background: pink
}
<div class="main-nav">Main Nav</div>
The final approach with some optimisations:
var mainNav = document.querySelector('.main-nav');
window.onscroll = function() {
windowScroll();
};
function windowScroll() {
mainNav.classList.toggle("test", mainNav.scrollTop > 50 || document.documentElement.scrollTop > 50);
}
html, body {
height: 150%;
}
.main-nav {
position: fixed;
width: 100%;
}
.test {
background: pink
}
<div class="main-nav">Main Nav</div>
The changes:
Store the .main-nav element on the global context (the window object). It will not change so you don't need to find it in any scroll.
Use querySelector so you will get a single DOM element, not collection.
Use classList.toggle to toggle the class by condition.
The issue with your console.log is that you're trying to pull the scrollTop for an HTML Collection (a collection of elements in your page) of 1 or more divs - therefore it can't check for the scrollTop as the console.log as it doesn't actually have that property.
Assuming you only have one element with the "main-nav" class (or there is a particular element with this class that you wish to apply it to), you would be better off using one of the following: document.getElementsByClassName("main-nav")[0] or document.getElementById("main-nav") (the latter would require you to create a main-nav id rather than a class).
For the first one, however, using className reassigns the class name rather than adding to that particular div, therefore you can use document.getElementsByClassName("main-nav")[0].classList.add("test") (and remove instead of add if it does not match your criteria).
If there is more than one element with the "main-nav" class, you can still use the first option I suggested - only you would need to wrap it around in a for loop and replace the 0 with your variable of choice.
for (i = 0; i < document.getElementsByClassName("main-nav").length; i++) {
//your code here using document.getElementsByClassName("main-nav")[i]
}

Resize on div element

jQuery has the resize() - event, but it just work with window.
jQuery(window).resize(function() { /* What ever */ });
This works fine! But when I want to add the event to a div element it doesn't work.
E.g.
jQuery('div').resize(function() { /* What ever */ });
I want to start an callback when the size of a div-element has changed. I don't want to start a resizable - event – just a event to check if the size of a div -
element has changed.
Is there any solution to do this?
DIV does not fire a resize event, so you won't be able to do exactly what you've coded, but you could look into monitoring DOM properties.
If you are actually working with something like resizables, and that is the only way for a div to change in size, then your resize plugin will probably be implementing a callback of its own.
I was only interested for a trigger when a width of an element was changed (I don' care about height), so I created a jquery event that does exactly that, using an invisible iframe element.
$.event.special.widthChanged = {
remove: function() {
$(this).children('iframe.width-changed').remove();
},
add: function () {
var elm = $(this);
var iframe = elm.children('iframe.width-changed');
if (!iframe.length) {
iframe = $('<iframe/>').addClass('width-changed').prependTo(this);
}
var oldWidth = elm.width();
function elmResized() {
var width = elm.width();
if (oldWidth != width) {
elm.trigger('widthChanged', [width, oldWidth]);
oldWidth = width;
}
}
var timer = 0;
var ielm = iframe[0];
(ielm.contentWindow || ielm).onresize = function() {
clearTimeout(timer);
timer = setTimeout(elmResized, 20);
};
}
}
It requires the following css :
iframe.width-changed {
width: 100%;
display: block;
border: 0;
height: 0;
margin: 0;
}
You can see it in action here widthChanged fiddle
// this is a Jquery plugin function that fires an event when the size of an element is changed
// usage: $().sizeChanged(function(){})
(function ($) {
$.fn.sizeChanged = function (handleFunction) {
var element = this;
var lastWidth = element.width();
var lastHeight = element.height();
setInterval(function () {
if (lastWidth === element.width()&&lastHeight === element.height())
return;
if (typeof (handleFunction) == 'function') {
handleFunction({ width: lastWidth, height: lastHeight },
{ width: element.width(), height: element.height() });
lastWidth = element.width();
lastHeight = element.height();
}
}, 100);
return element;
};
}(jQuery));
I've created jquery plugin jquery.resize it use resizeObserver if supported or solution based on marcj/css-element-queries scroll event, no setTimeout/setInterval.
You use just
jQuery('div').on('resize', function() { /* What ever */ });
or as resizer plugin
jQuery('div').resizer(function() { /* What ever */ });
I've created this for jQuery Terminal and extracted into separated repo and npm package, but in a mean time I switched to hidden iframe because I had problems with resize if element was inside iframe. I may update the plugin accordingly. You can look at iframe based resizer plugin in jQuery Terminal source code.
EDIT: new version use iframe and resize on it's window object because the previous solutions was not working when page was inside iframe.
EDIT2: Because the fallback use iframe you can't use it with form controls or images, you need to add it to the wrapper element.
EDIT3:: there is better solution using resizeObserver polyfill that use mutation observer (if resizeObserver is not supported) and work even in IE. It also have TypeScript typings.
what about this:
divH = divW = 0;
jQuery(document).ready(function(){
divW = jQuery("div").width();
divH = jQuery("div").height();
});
function checkResize(){
var w = jQuery("div").width();
var h = jQuery("div").height();
if (w != divW || h != divH) {
/*what ever*/
divH = h;
divW = w;
}
}
jQuery(window).resize(checkResize);
var timer = setInterval(checkResize, 1000);
BTW I suggest you to add an id to the div and change the $("div") to $("#yourid"), it's gonna be faster, and it won't break when later you add other divs
There is a really nice, easy to use, lightweight (uses native browser events for detection) plugin for both basic JavaScript and for jQuery that was released this year. It performs perfectly:
https://github.com/sdecima/javascript-detect-element-resize
Only window is supported yes but you could use a plugin for it: http://benalman.com/projects/jquery-resize-plugin/
There now exists Resize Observer
You could use it like so:
const resizeObserver = new ResizeObserver((entries) => {
entries.forEach(console.log);
})
resizeObserver.observe(document.getElementById("ExampleElement"));
For a google maps integration I was looking for a way to detect when a div has changed in size. Since google maps always require proper dimensions e.g. width and height in order to render properly.
The solution I came up with is a delegation of an event, in my case a tab click. This could be a window resize of course, the idea remains the same:
if (parent.is(':visible')) {
w = parent.outerWidth(false);
h = w * mapRatio /*9/16*/;
this.map.css({ width: w, height: h });
} else {
this.map.closest('.tab').one('click', function() {
this.activate();
}.bind(this));
}
this.map in this case is my map div.
Since my parent is invisible on load, the computed width and height are 0 or don't match.
By using .bind(this) I can delegate the script execution (this.activate) to an event (click).
Now I'm confident the same applies for resize events.
$(window).one('resize', function() {
this.div.css({ /*whatever*/ });
}.bind(this));
Hope it helps anyone!
You can change your text or Content or Attribute depend on Screen size:
HTML:
<p class="change">Frequently Asked Questions (FAQ)</p>
<p class="change">Frequently Asked Questions </p>
Javascript:
<script>
const changeText = document.querySelector('.change');
function resize() {
if((window.innerWidth<500)&&(changeText.textContent="Frequently Asked Questions (FAQ)")){
changeText.textContent="FAQ";
} else {
changeText.textContent="Frequently Asked Questions (FAQ)";
}
}
window.onresize = resize;
</script>
document.addEventListener('transitionend', function(e) {
if ($(e.target).is("div")) {
$("div").text("width: "+$("div").width());
}
});
$("div").css({"width":"150px"});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="width: 100px;transition-delay: 0.000000001s;">width: 100</div>
A very simple implementation.
<script>
var move = function(e) {
if ((e.w && e.w !== e.offsetWidth) || (e.h && e.h !== e.offsetHeight)) {
new Function(e.getAttribute('onresize')).call(e);
}
e.w = e.offsetWidth;
e.h = e.offsetHeight;
}
var resize = function() {
console.log('Resized')
}
</script>
<style>
.resizable {
resize: both;
overflow: auto;
width: 200px;
border: 1px solid black;
padding: 20px;
}
</style>
<div class='resizable' onresize="resize(this)" onmousemove="move(this)">
Pure vanilla implementation
</div>
If you just want to resize the div itself you need to specify that in css style. You need to add overflow and resize property.
Below is my code snippet
#div1 {
width: 90%;
height: 350px;
padding: 10px;
border: 1px solid #aaaaaa;
overflow: auto;
resize: both;
}
<div id="div1">
</div>

Categories

Resources