I am trying to create a multiple items per slide carousel that i need to change the number of items per slide with different screen breakpoints.
For example, i want to show 4 items per slide when window width is bigger than 1200px, 3 between (992px - 1200px), 2 between (768 - 992px) and 1 for smaller screens.
The idea that i got in my mind is to make an event that change a state when a certain breakpoint reached:
state: {
itemsNum: 1
}
const createSlides = () => {
let slides = [];
let itemsNum = this.state.itemsNum;
for (let i = 0; i < products.length ; i = i + itemsNum) {
slides.push(products.slice(i, i + itemsNum))
}
return slides;
}
const slides = createSlides ();
slides.map (........)// rendering the items in the slide
This is just the incomplete idea in my mind, but i need the complete solution that make this idea work successfully.
What is the better way to achieve that in the term of react??
You can use window.onresize.
window.onresize = function(event) {
... };
Well, to talk about my opinion, you can use "event handlers".
Like this: window.addEventListener('onresize', createSlides)
As the time goes, I didn't complete the whole things through, but if you want to know more about this or you are interested in this method, I can tell you the exact method.
Related
I have the following mockup:
Until now, I managed to do the following which is pretty close: https://codesandbox.io/s/codepen-with-react-forked-16t6rv?file=/src/components/TrendingNFTs.js
I have the following problems that I'm trying to tackle:
When pressing the next and previous buttons, the component seems to reset, what I want is to stop there in case the element is the last on the list
I'm find the progress bar below the cards with the arrows hard to implement and I want to ask if you guys have ever seems something that comes close to this.
Thanks in advance, if something is willing to help me with some ideas at least.
You can take let count = 0 at the start and update rest of the code as
const shiftPrev = (copy) => {
let lastcard = copy.pop();
if (count > 0) {
copy.splice(0, 0, lastcard);
setCarouselItems(copy);
}
};
const shiftNext = (copy) => {
let firstcard = copy.shift();
if (count < copy.length) {
copy.splice(copy.length, 0, firstcard);
setCarouselItems(copy);
}
};
The logic is you take the initial count (you can also keep your count in state but on setState it will re-render which might cause performance issue later)
Also, please consider adding css and the initial card its displaying on UI and set your start/end count accordingly.
In order to get an animation to work, I am trying to update data in a method consecutively, but the updates are happening to fast.
The element in question was previously animated by setting a custom property --int-menu-height to a height, retrieved via a $ref. A transitionend event is then setting that variable to auto. Now to get the same transition into the other direction, I need to first remove the auto and replace it with an interpolatable value, and then set it to zero, so that it animates between those two values. There is another transitionend event waiting, to finish the entire interaction. This is what my code for the closing looks like, right now:
const comp = this;
const menu = this.$refs.menu;
const menuHeight = this.$refs.menuHeight.clientHeight+'px';
// set it too the actual height (from previously 'auto')
this.menuStyles = { '--int-menu-height': menuHeight };
this.$nextTick( () => {
// set it to zero, so that it animates
this.menuStyles = { '--int-menu-height': 0 }
});
// never firing, because no transition
menu.addEventListener('transitionend', function closeMenu() {
comp.isMenuOpen = false;
menu.removeEventListener('transitionend', closeMenu);
});
I'm thought that $nextTick() would do the trick, but it is still happening to fast. How can I update this.menuStyles only after making sure that the previous update has fully rendered through?
Like Radeanu pointed out, I can just use setTimeout(). Because $nextTick() fires after an update in the virtual DOM, not in the real DOM. The code that I use now, that works, looks like this:
setTimeout( () => {
// set it to zero, so that it animates
this.menuStyles = { '--int-menu-height': 0 }
}, 1);
I'm trying to solve 2 problems with this project:
Flip the cards back when no match is made.
Once the randomization occurs, allow the user to briefly show all the randomized cards for x seconds before the game timer commences.
At one point I was able to flip the unmatched cards, but I lost that ability whilst trying to sort out problem #2.
For #1 I first declared a variable:
const pix = document.querySelectorAll('.card img');
Then I did an if/else to hide unmatched:
function checkForMatch() {
if (
toggledCards[0].firstElementChild.className === toggledCards[1].firstElementChild.className) {
toggledCards[0].classList.toggle('match');
toggledCards[1].classList.toggle('match');
toggledCards = [];
matched++;
} else {
setTimeout(() => {
toggleCard(toggledCards[0]);
toggleCard(toggledCards[1]);
toggledCards = [];
// Trying to hide unmatchaed cards here
pix.style.display = "none";
}, 1000);
}
};
That fails and I cannot figure out why.
As Sheng Slogar have mentioned, You don't have class names on your img tags so it doesn't work. I added some to check and it was working, so just add classes with numbers to images and it will work properly :)
I also recommend to use data attributes for this kind of functionality as it's exactly what they are made for.
I have this simple "pagination" counter which is fetching the next page from an API. It works fine but the problem is that whenever I change category (movies or series) the counter obviously doesn't reset so instead of fetching the first page of the new category it continues from the number it left off.
I tried numerous conditional combinations but nothing really worked so far. I'm sure it's not that hard to solve I just can't think of the right logic to use.
let page = 1;
document.getElementById('load-more').addEventListener('click', () => {
page++;
const movies = document.getElementById('movies');
const series = document.getElementById('series');
if(movies.classList.contains('active-link')) {
getMovies(page);
} else if (series.classList.contains('active-link')) {
getSeries(page);
}
})
Reseting the let counter inside the if..else doesn't really work because every time I click the load more button it resets it back to page 1.
Use separate variables for the current movies page and the current series page. Also note that you can simplify your logic by using a single querySelector instead of selections followed by classList.contains:
let moviesPage = 1;
let seriesPage = 1;
document.getElementById('load-more').addEventListener('click', () => {
if (document.querySelector('#movies.active-link')) {
moviesPage++;
getMovies(moviesPage);
} else if (document.querySelector('#series.active-link')) {
seriesPage++;
getSeries(seriesPage);
}
});
Set another event listener for the click on your #movies and #series link,
and set the page variable to 1 at this place.
That would be the usual behavior when switching lists, one usually see a reset of paging.
I'm working on a responsive site with a specific set of jQuery functions for the desktop layout and mobile layout. They interfere with each other if they're both active at the same time.
By checking window.width, I'm able to deliver only the correct set of functions on page load, and I'd like to do the same on window.resize.
I've set up a stripped down Fiddle of where I'm at here: http://jsfiddle.net/b9XEj/
Two problems exist right now:
Either desktopFunctions or mobileFunctions will continuously fire on page resize, whether they have already been loaded or not.
If the window is resized beyond one breakpoint and then returned to the previous size, the incorrect set of functions will already have been loaded, interfering with the current set.
The window.resize function should behave in the following way:
Check if the correct set of functions currently active for the viewport size
If yes, return.
If no, fire correct set of functions and remove incorrect set of functions if they exist.
In the Fiddle example above, you would always see a single line, displaying either "Mobile Functions are active" or "Desktop Functions are active".
I'm a bit lost at this point, but I have tried using
if ($.isFunction(window.mobileFunctions))
to check if functions already exist, but I can't seem to get it working without breaking the overall function. Here's a fiddle for that code: http://jsfiddle.net/nA8TB/
Thinking ahead, this attempt also wouldn't take into account whether the incorrect set of functions exists already. So, I'm really hoping there's a way I can deal with this in a simpler way and solve both problems.
Any help would be much appreciated!
Following conquers 2 of the problems. The resize fires many times a second, so using a timeout will fix it firing your code constantly. It also adds a check to see if the same size is in effect, and return if it is
$(document).ready(function() {
var windowType;
var $wind = $(window);
var desktopFunctions = function() {
$('body').append('<p>Desktop functions are active</p>');
}
var mobileFunctions = function() {
$('body').append('<p>Mobile Functions are active</p>');
}
var mobileCheck = function() {
var window_w = $wind.width();
var currType = window_w < 940 ? 'mobile' :'desktop';
if (windowType == currType) {
$('body').append('<p>No Type Change, Width= '+window_w+'</p>');
return;
} else {
windowType = currType;
}
if (windowType == 'mobile') {
mobileFunctions();
} else {
desktopFunctions();
}
}
mobileCheck();
var resizeTimer;
$wind.resize(function() {
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(mobileCheck, 300)
});
});
DEMO: http://jsfiddle.net/b9XEj/1/
Without seeing some real world differences between your 2 sets of functions it is hard to provide gudance on how to stop them conflicting. One possibility is checking the windowType in your functions
You can prevent the continuous firing by adding a delay mobileCheck. Use a setTimeout along with a checkPending boolean value.
var checkPending = false;
$(window).resize(function(){
if (checkPending === false) {
checkPending = true;
setTimeout(mobileCheck, 1000);
}
});
See here: http://jsfiddle.net/2Q3pT/
Edit
As far as the second requirement, you could use this pattern to create or use the existing one:
mobileFunctions = mobileFunctions || function() {
// mobile functions active
};
See: http://jsfiddle.net/2Q3pT/2/