I really need some help with media queries. I have made a testimonial slider and when it gets to a 800px breakpoint, I want to disable the JS for the slider and change the layout.
The problem is that I am unable to deactivate the js once it has been activated, I'm not sure if the problem is from the event handler, the if statement of from the deactivation function.
I have managed to deactivate the JS but I have to reload the page to do it, I want it to be responsive so that I don't have to reload the page every time.
If you can help, that would be a huge help, thanks!
Here is my JS code:
(All my css code works, hence, it hasn't been added).
const mQ = window.matchMedia('(max-width: 800px)');
const testimonialSlider = function () {
const slides = document.querySelectorAll('.slide');
const btnLeft = document.querySelector('.slider__btn--left');
const btnRight = document.querySelector('.slider__btn--right');
const dotContainer = document.querySelector('.dots');
const testimonialContainer = document.querySelector(
'.testimonial-outer-container'
);
//Deactivate functions
const deactivateJs = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${0 * (i - slide)}%)`)
);
testimonialContainer.removeChild(dotContainer);
console.log('DeactivatingJs');
};
// Activate functions
const activateJs = function () {
console.log('ActivateJS');
let curSlide = 0;
const maxSlide = slides.length;
//Functions
const createDots = function () {
testimonialContainer.appendChild(dotContainer);
slides.forEach(function (_, i) {
dotContainer.insertAdjacentHTML(
'beforeend',
`<button class="dots__dot" data-slide="${i}"></button>`
);
});
};
const slideReady = function () {
createDots();
activateDot(0);
goToSlide(0);
};
const goToSlide = function (slide) {
slides.forEach(
(s, i) => (s.style.transform = `translateX(${100 * (i - slide)}%)`)
);
};
// Activate dots
const activateDot = function (slide) {
// First we remove the active class on all of the dots and then we add it to the one that it is active
document
.querySelectorAll('.dots__dot')
.forEach(dot => dot.classList.remove('dots__dot--active'));
document
.querySelector(`.dots__dot[data-slide="${slide}"]`)
.classList.add('dots__dot--active');
};
// Next slide
const nextSlide = function () {
if (curSlide === maxSlide - 1) {
curSlide = 0;
} else {
curSlide++;
}
goToSlide(curSlide);
activateDot(curSlide);
};
const prevSlide = function () {
if (curSlide === 0) {
curSlide = maxSlide - 1;
} else {
curSlide--;
}
goToSlide(curSlide);
activateDot(curSlide);
};
slideReady();
//Event Handlers
btnRight.addEventListener('click', nextSlide);
btnLeft.addEventListener('click', prevSlide);
// Creating an event with the arrows
document.addEventListener('keydown', function (e) {
console.log(e);
if (e.key === 'ArrowLeft') prevSlide();
if (e.key === 'ArrowRight') nextSlide();
});
dotContainer.addEventListener('click', function (e) {
if (e.target.classList.contains('dots__dot')) {
/// const slide = e.target.dataset.slide;
//This is the same as above, the slide part is from the html and the dataset is an HTML attribute
const { slide } = e.target.dataset;
goToSlide(slide);
activateDot(slide);
}
});
};
// if (mQ.matches) {
// deactivateJs();
// } else {
// activateJs();
// }
const js = function () {
if (mQ.matches) {
console.log('deactivate');
deactivateJs();
} else {
activateJs();
}
};
mQ.addEventListener('change', js);
};
testimonialSlider();
Related
I have this problem: I have two buttons btStop and btRace . BtPlays clicks all the buttons bt1 and all my cars are driving at the same time. BtStop works exactly the same but it stops the animation. My problem is, that when I once click btRace and animation is done I cannot click it again unless I click btStop, which is misleading because animation is already stopped.
Is there a way to make btPlay active again after the animation is finished?
I have long code so I am pasting showButtons method
showButtons(bt1, bt2, img, editingCarId) {
let playBts = document.querySelectorAll('.play')
function animation(img) {
let status = 'started';
let aPICallCarEngineState = new APICallCarEngineState(editingCarId, status);
aPICallCarEngineState.processRequestJSON((res) => {
// let resStr = JSON.stringify(res);
// console.log('I got ' + res)
res.velocity = res.velocity * 0.01
// res.distance = res.distance * 0.001
res.distance = 500;
// ===========Animation===================
img.style.animation = `car_move ${res.velocity}s ease-in`
})
}
//================Stop Animation===============
function stopAnimation() {
img.style.animation = 'none'
console.log(bt2 + 'stopp')
}
bt1.addEventListener('click', () => {
animation(img)
});
bt2.addEventListener('click', () => {
stopAnimation()
})
//=================Button start all animations ====================
this.btRace.addEventListener('click', () => {
bt1.click();
})
//=================Button stop all animations ====================
this.btStop.addEventListener('click', () => {
bt2.click();
})
}
invoke:
constructor:
this.table.appendTableHeadButton('RACE!')
this.table.appendTableHeadButtonStop('stop')
Buttoncreator:
appendTableHeadButtonStop(text) {
let td = document.createElement('td');
this.btStop = document.createElement('button');
this.btStop.innerText = text;
this.btStop.style.backgroundColor = 'red';
td.appendChild(this.btStop);
let bt = this.btStop;
this.headeRow.appendChild(td);
}
showButtons(bt1, bt2, img, editingCarId) {
let playBts = document.querySelectorAll('.play')
let isAnimating = false;
function animation(img) {
isAnimating = true;
btRace.disabled = true;
let status = 'started';
let aPICallCarEngineState = new APICallCarEngineState(editingCarId, status);
aPICallCarEngineState.processRequestJSON((res) => {
// let resStr = JSON.stringify(res);
// console.log('I got ' + res)
res.velocity = res.velocity * 0.01
// res.distance = res.distance * 0.001
res.distance = 500;
// ===========Animation===================
img.style.animation = `car_move ${res.velocity}s ease-in`
img.addEventListener('animationend', () => {
isAnimating = false;
btRace.disabled = false;
});
});
}
//================Stop Animation===============
function stopAnimation() {
isAnimating = false;
btRace.disabled = false;
img.style.animation = 'none'
console.log(bt2 + 'stopp')
}
bt1.addEventListener('click', () => {
animation(img)
});
bt2.addEventListener('click', () => {
stopAnimation()
});
//=================Button start all animations ====================
this.btRace.addEventListener('click', () => {
bt1.click();
});
//=================Button stop all animations ====================
this.btStop.addEventListener('click', () => {
bt2.click();
});
}
I am adding a flag to check the state of animation, and then toggle disabled property of btRace button respectively.
I have a slider and I want to add auto play every 3 seconds. I tried to use SetInterval but nothing happened.
Also I would like to remove the code for removing elements from the slider. I want to remove all the controls also and have only the slider changing image every 3 seconds.
this is the slider code
const galleryContainer = document.querySelector('.gallery-container');
const galleryControlsContainer = document.querySelector('.gallery-controls');
const galleryControls = ['Предидущий', '', 'Следующий'];
const galleryItems = document.querySelectorAll('.gallery-item');
class Carousel {
constructor(container, items, controls) {
this.carouselContainer = container;
this.carouselControls = controls;
this.carouselArray = [...items];
}
updateGallery() {
this.carouselArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
});
this.carouselArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
}
setCurrentState(direction) {
if (direction.className == 'gallery-controls-previous') {
this.carouselArray.unshift(this.carouselArray.pop());
} else {
this.carouselArray.push(this.carouselArray.shift());
}
this.updateGallery();
}
setControls() {
this.carouselControls.forEach(control => {
galleryControlsContainer.appendChild(document.createElement('button')).className = `gallery-controls-${control}`;
document.querySelector(`.gallery-controls-${control}`).innerText = control;
});
}
useControls() {
const triggers = [...galleryControlsContainer.childNodes];
triggers.forEach(control => {
control.addEventListener('click', e => {
e.preventDefault();
if (control.className == 'gallery-controls-add') {
const newItem = document.createElement('img');
const latestItem = this.carouselArray.length;
const latestIndex = this.carouselArray.findIndex(item => item.getAttribute('data-index') == this.carouselArray.length)+1;
Object.assign(newItem,{
className: 'gallery-item',
src: `http://fakeimg.pl/300/?text=${this.carouselArray.length+1}`
});
newItem.setAttribute('data-index', this.carouselArray.length+1);
this.carouselArray.splice(latestIndex, 0, newItem);
document.querySelector(`[data-index="${latestItem}"]`).after(newItem);
this.updateGallery();
} else {
this.setCurrentState(control);
}
});
});
}
}
const exampleCarousel = new Carousel(galleryContainer, galleryItems, galleryControls);
exampleCarousel.setControls();
exampleCarousel.useControls();
See the below code, I have added auto slide functionality with interval time 5 seconds.
If you want to change the interval, Please update the setInterval time in the "constructor" and "setCurrentState" functions.
I have removed the controls. To remove the controls, we need to comment the last 2 lines
//exampleCarousel.setControls();
//exampleCarousel.useControls();
const galleryContainer = document.querySelector('.gallery-container');
const galleryControlsContainer = document.querySelector('.gallery-controls');
const galleryControls = ['Предидущий', '', 'Следующий'];
const galleryItems = document.querySelectorAll('.gallery-item');
class Carousel {
constructor(container, items, controls) {
this.carouselContainer = container;
this.carouselControls = controls;
this.carouselArray = [...items];
this.mySlideInterval = null;
this.mySlideInterval = setInterval(
this.autoSlide.bind(this),
5000
);
}
autoSlide() {
this.carouselArray.push(this.carouselArray.shift());
this.updateGallery();
}
updateGallery() {
this.carouselArray.forEach(el => {
el.classList.remove('gallery-item-1');
el.classList.remove('gallery-item-2');
el.classList.remove('gallery-item-3');
el.classList.remove('gallery-item-4');
el.classList.remove('gallery-item-5');
});
this.carouselArray.slice(0, 5).forEach((el, i) => {
el.classList.add(`gallery-item-${i+1}`);
});
}
setCurrentState(direction) {
if (direction.className == 'gallery-controls-previous') {
this.carouselArray.unshift(this.carouselArray.pop());
} else {
this.carouselArray.push(this.carouselArray.shift());
}
clearInterval(this.mySlideInterval);
this.updateGallery();
this.mySlideInterval = setInterval(
this.autoSlide.bind(this),
5000
);
}
setControls() {
this.carouselControls.forEach(control => {
galleryControlsContainer.appendChild(document.createElement('button')).className = `gallery-controls-${control}`;
document.querySelector(`.gallery-controls-${control}`).innerText = control;
});
}
useControls() {
const triggers = [...galleryControlsContainer.childNodes];
triggers.forEach(control => {
control.addEventListener('click', e => {
e.preventDefault();
if (control.className == 'gallery-controls-add') {
const newItem = document.createElement('img');
const latestItem = this.carouselArray.length;
const latestIndex = this.carouselArray.findIndex(item => item.getAttribute('data-index') == this.carouselArray.length)+1;
Object.assign(newItem,{
className: 'gallery-item',
src: `http://fakeimg.pl/300/?text=${this.carouselArray.length+1}`
});
newItem.setAttribute('data-index', this.carouselArray.length+1);
this.carouselArray.splice(latestIndex, 0, newItem);
document.querySelector(`[data-index="${latestItem}"]`).after(newItem);
this.updateGallery();
} else {
this.setCurrentState(control);
}
});
});
}
}
const exampleCarousel = new Carousel(galleryContainer, galleryItems, galleryControls);
//exampleCarousel.setControls();
//exampleCarousel.useControls();
I need to callback. a. function after setting a state within a nested function which triggers on click, How can I approach this, I know that calling hooks in nested functions doesn't work but it's necessary in my case. I tried using useEffect and useCallback but as expected it wont work The code looks like this in a nutshell:
const App = () => {
const [elements, setElements] = useState(true);
function UseEffectSkipFirst(fn, arr) {
const isFirst = useRef(true);
useCallback(() => {
if (isFirst.current) {
isFirst.current = false;
return;
}
fn();
}, arr);
}
const Shape = (g) => {
// let colorMatrix = new PIXI.filters.ColorMatrixFilter();
// let color = 0xffffff
// let tint = 0xffffff;
function onClick(event) {
setElements(false);
UseEffectSkipFirst(
() => {
if (elements === true) {
this.data = event.data;
this.dragging = true;
this.offX = this.x - this.data.getLocalPosition(this.parent).x;
this.offY = this.y - this.data.getLocalPosition(this.parent).y;
} else {
g.clear();
}
},
[elements]
);
}
// ...
};
return (
//...
);
};
can anyone help please, thanks
I installed Shuffle.js from a codepen demo with some customizations to style and figure cards. I've added in recommended js code but the shuffle function doesn't seem work.
Getting several errors:
console errors
I've tried updating script based on some past answers to this problem. I've also downloaded and added the actual js file on my site and referenced it in the script. Here's what my script looks like right now:
<script src="/v/vspfiles/assets/js/shuffle.js"></script>
<script>
'use strict';
var Shuffle = window.shuffle;
var Demo = function (element) {
this.element = element;
// Log out events.
this.addShuffleEventListeners();
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
this._activeFilters = [];
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
this.mode = 'exclusive';
};
Demo.prototype.toArray = function (arrayLike) {
return Array.prototype.slice.call(arrayLike);
};
Demo.prototype.toggleMode = function () {
if (this.mode === 'additive') {
this.mode = 'exclusive';
} else {
this.mode = 'additive';
}
};
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example). The extra event
* data is in the `detail` property.
*/
Demo.prototype.addShuffleEventListeners = function () {
var handler = function (event) {
console.log('type: %s', event.type, 'detail:', event.detail);
};
this.element.addEventListener(Shuffle.EventType.LAYOUT, handler, false);
this.element.addEventListener(Shuffle.EventType.REMOVED, handler, false);
};
Demo.prototype.addFilterButtons = function () {
var options = document.querySelector('.filter-options');
if (!options) {
return;
}
var filterButtons = this.toArray(
options.children
);
filterButtons.forEach(function (button) {
button.addEventListener('click', this._handleFilterClick.bind(this), false);
}, this);
};
Demo.prototype._handleFilterClick = function (evt) {
var btn = evt.currentTarget;
var isActive = btn.classList.contains('active');
var btnGroup = btn.getAttribute('data-group');
// You don't need _both_ of these modes. This is only for the demo.
// For this custom 'additive' mode in the demo, clicking on filter buttons
// doesn't remove any other filters.
if (this.mode === 'additive') {
// If this button is already active, remove it from the list of filters.
if (isActive) {
this._activeFilters.splice(this._activeFilters.indexOf(btnGroup));
} else {
this._activeFilters.push(btnGroup);
}
btn.classList.toggle('active');
// Filter elements
this.shuffle.filter(this._activeFilters);
// 'exclusive' mode lets only one filter button be active at a time.
} else {
this._removeActiveClassFromChildren(btn.parentNode);
var filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
this.shuffle.filter(filterGroup);
}
};
Demo.prototype._removeActiveClassFromChildren = function (parent) {
var children = parent.children;
for (var i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
}
};
Demo.prototype.addSorting = function () {
var menu = document.querySelector('.sort-options');
if (!menu) {
return;
}
menu.addEventListener('change', this._handleSortChange.bind(this));
};
Demo.prototype._handleSortChange = function (evt) {
var value = evt.target.value;
var options = {};
function sortByDate(element) {
return element.getAttribute('data-created');
}
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
this.shuffle.sort(options);
};
// Advanced filtering
Demo.prototype.addSearchFilter = function () {
var searchInput = document.querySelector('.js-shuffle-search');
if (!searchInput) {
return;
}
searchInput.addEventListener('keyup', this._handleSearchKeyup.bind(this));
};
/**
* Filter the shuffle instance by items with a title that matches the search input.
* #param {Event} evt Event object.
*/
Demo.prototype._handleSearchKeyup = function (evt) {
var searchText = evt.target.value.toLowerCase();
this.shuffle.filter(function (element, shuffle) {
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
var groups = JSON.parse(element.getAttribute('data-groups'));
var isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
}
}
var titleElement = element.querySelector('.picture-item__title');
var titleText = titleElement.textContent.toLowerCase().trim();
return titleText.indexOf(searchText) !== -1;
});
};
document.addEventListener('DOMContentLoaded', function () {
window.demo = new Demo(document.getElementById('grid'));
});
</script>
Any insight into what I need to remedy to get this working properly would be great. Thanks!
I have multiple HTML videos on my page, and want to apply this custom video player to them. The thing is, this only works for the first video, and not for the second, third and fourth.
I have no idea where to start.
I made a fiddle of the current state: JSFiddle
My Javascript
/* Get Our Elements */
const player = document.querySelector('.player');
const video = player.querySelector('.viewer');
const progress = player.querySelector('.progress');
const progressBar = player.querySelector('.progress__filled');
const toggle = player.querySelector('.toggle');
const skipButtons = player.querySelectorAll('[data-skip]');
const ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
I want this script to work on every video element on the page:
JSFiddle
Thanks,
Max
You can try something like this :
/* Get Our Elements */
$('.player').each(function() {
var player = $(this).get(0);
var video = player.querySelector('.viewer');
var progress = player.querySelector('.progress');
var progressBar = player.querySelector('.progress__filled');
var toggle = player.querySelector('.toggle');
var skipButtons = player.querySelectorAll('[data-skip]');
var ranges = player.querySelectorAll('.player__slider');
/* Build out functions */
function togglePlay() {
const method = video.paused ? 'play' : 'pause';
video[method]();
}
function updateButton() {
const icon = this.paused ? '►' : '❚❚';
toggle.textContent = icon;
}
function skip() {
video.currentTime += parseFloat(this.dataset.skip);
}
function handleRangeUpdate() {
video[this.name] = this.value;
}
function handleProgress() {
const percent = (video.currentTime / video.duration) * 100;
progressBar.style.flexBasis = `${percent}%`;
}
function scrub(e) {
const scrubTime = (e.offsetX / progress.offsetWidth) * video.duration;
video.currentTime = scrubTime;
}
/* Hook up the event listners */
video.addEventListener('click', togglePlay);
video.addEventListener('play', updateButton);
video.addEventListener('pause', updateButton);
video.addEventListener('timeupdate', handleProgress);
toggle.addEventListener('click', togglePlay);
skipButtons.forEach(button => button.addEventListener('click', skip));
ranges.forEach(range => range.addEventListener('change', handleRangeUpdate));
ranges.forEach(range => range.addEventListener('mousemove', handleRangeUpdate));
let mousedown = false;
progress.addEventListener('click', scrub);
progress.addEventListener('mousemove', (e) => mousedown && scrub(e));
progress.addEventListener('mousedown', () => mousedown = true);
progress.addEventListener('mouseup', () => mousedown = false);
$('video').on('ended', function() {
$.fn.fullpage.moveSlideRight();
});
});
https://jsfiddle.net/kq5hdw0m/