Why scrollIntoView only work inside of setTimeout? - javascript

i want to use scrollIntoView function.
i wrote code like this
viewRef.current.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest',});
but it doesn't work at first click. it start working with the second click.
When I click for the first time, it doesn't seem to work because there's no content. So I thought, There should be a click and a time interval.
So i modified code like this
setTimeout(
() =>
viewRef.current?.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest',
}),
10
);
then it works at first click
but i want to know why it works inside of setTimeout??
And, it doesn't work or work occasionally when setTimeout(()=>scrollIntoView, 0 or 1 or ... 5)
why work occasionally when i set time 0 - 5 ?

Related

Cypress - click on element when not disabled

I have an anchor in an Angular app which is disabled until the page content loads, which takes some time.
Is there any way to click it only after it stops being disabled?
I tried with:
const myItems = cy.get('whatever-selectors');
myItems.contains('some text', {timeout: 10000}).should('not.be.disabled').click();
This doesn't work.
The documentation states that Cypress will retry clicking until the should condition is fulfilled or the timeout is exceeded, but it fails after less than half the time.
Any suggestions?
You should apply the timeout: 10000 with cy.get()
cy.get('whatever-selectors', {
timeout: 20000
}).should('be.enabled').click();
The problem here is that ,,should" is an assertion. To trigger a click event, cypress has to find an element first.
For this case usually worth to use a pseudo selector like
cy.get('whatever-selectors:not([disabled])').click();
In case of the loading takes more time than the default configuration you can alter the line like
cy.get('whatever-selectors:not([disabled])', { timeout: 10000 }).click();

Since updating animejs my javascript no longer functions

Essentially I had an 'animejs' animation trigger when the nav button is clicked and then the same animation would reverse after a second click. It would toggle. Now this no longer works after updating animejs.
I've tried using a variable such as
var playing = true; and to toggle between it but that doesn't possess the same functionality as before.
the code looked something like this (this is simplified)
var navAnimation = anime.timeline({
duration: 100,
});
animation.add({
targets: 'navStuff'
//animation would be here
});
document.querySelector('.nav').onclick = () => {
animation.play();
// animation.play still functions properly
animation.reverse();
// animation.reverse(); is broken
};
//before the update you could simply place a two methods within the onclick function and it would toggle between them but that no longer is the case with animejs
What I want to happen is to be able to use a single target (button) to open my navigation and close it (toggle between the two state). I want to be able to spam the button and not see and glitches (as before).
Please beleive me I've spent an uncessary amount of time trying to get this working and it just refused to giv in.
I've attempted working with heights / transforms / colors, variable diffs, close inspection. Nothing works.
This is how I animate "reverses" now:
const notificationsContainerElement = document.querySelector('#demo-install-notifications-container');
let notificationsContainerAnimation = anime({
targets: notificationsContainerElement,
height: '350px',
easing: 'easeOutElastic(1.5, .5)',
duration: 1500,
delay: 0,
autoplay: false,
});
notificationsContainerElement.addEventListener('click', () => {
if(notificationsContainerAnimation.began === false) {
notificationsContainerAnimation.play();
} else if(notificationsContainerAnimation.began === true) {
notificationsContainerAnimation.began = false;
anime({
targets: notificationsContainerElement,
height: '100px',
easing: 'easeOutElastic(1.5, .5)',
duration: 1500,
delay: 0,
});
}
});
My first animation is autoplay: false, then, when I click an element, I .play() that animation, but notice the checks for the original animation's began. Once you hit play on an animation, the began property keeps changing.
Right...
But just doing notificationsContainerAnimation.reverse() on my animation just doesn't work no matter what. It just doesn't. I strongly believe it has to do with anime not being able to get where it's supposed to actually reverse to - the values.
The logic is sound, there's no way why it shouldn't work...but it doesn't.
So, for now, use 2 animations.

How to set SWIPER start with the first slide?

I have an issue with the swiper (http://www.idangero.us/sliders/swiper/api.php)... I am on page 1 and when I swich to the page 2 I want the slider to start with the first slide. I set mySwiper.swipeTo(0, 0, false); on pagebeforeshow and it doesnt work. the STRANGEST thing is that it works perfectly if I swich to second or third slide (ex mySwiper.swipeTo(1, 0, false) or mySwiper.swipeTo(2, 0, false)) but on the first one (0) it simply doesn't swich. Why is that? I tried every possible thing. It doesn't switch on the first slide, only on others. The only method that works is onpageshow but its ugly because first it shows one slide and after another..
I also tried with mySwiper.swipePrev(); a few times but its blocking on slide 2.. It wont go on the first slide.
UPDATE:
here's the jsfiddle example: http://jsfiddle.net/alecstheone/9VBha/103/
so... if I go to second page and I swipe to the third slide than I right click and go back, than back to page 2 the swiper is still on the slide 3 and it should be on page 1 as I set
mySwiper.swipeTo(0, 1, true);
If I set:
mySwiper.swipeTo(1, 1, true);
or
mySwiper.swipeTo(2, 1, true);
it works... only on 0 it wont...
I also noticed that in the 1.8.0 version of the swiper it works that command, but in the latest (2.6.0) it wont.
const swiper2 = new Swiper('.swiper-container2', {
direction: 'vertical',
slidesPerView: 1,
initialSlide: 2,
});
you can use initialSlide to set first slide
If you look up the method swipeTo() in the library you'll find the following condition:
if (index > (_this.slides.length - 1) || index < 0) return;
Which indicates you can only use this method from index 1.
Why don't you just initialize the plugin without the pageBeforeShow option? It should take the first slide.
UPDATE
Finally got it to work and I also hope the author reads this since this is a terrible library to setup as the configuration parameters go berzerk throughout the whole script.
$(page2).click(function () {
//mySwiper.activeIndex = 0;
//mySwiper.startAutoplay();
//mySwiper.swipeReset();
//mySwiper.reInit(true);
setTimeout(function(){
// to make sure the swiper-wrapper is shown after the animation of $.mobile.changePage()
mySwiper.swipeTo(0);
}, 200);
$.mobile.changePage(page2);
// $("#photo").hide().delay(1000).fadeOut();
// $("#photo").animate({opacity: 0.0}, 1);
});
As you can see, the commented functionality seems straightforward but only brings frustration to the people using this. For me this is a design flaw in naming convention and boolean traps.
I also noticed you set height and width dynamically and I'm sure there "is a way" to let the script calculate these parameters as it uses a polyfill for getComputedStyle(). Or you might try to use CSS3 calc() to take some performance hit out of JS.
Second time I use this library and again I had to use the unminified version to debug the functions and it's parameter setup which doesn't work together very well. Only a set of combinations can make this library work and it's up to the developer to figure this whole bunch out.
Good luck on the script and note that the provided code really helped (very quickly) in understanding the problem.
DEMO
I had the same problem few months after this discussion.
I know it's a ugly way to fix the problem, but its the only way I found :
When you call mySwiper.swipeTo(0), this line below :
if (newPosition === currentPosition) return false;
will return false and not apply the swipe, because newPosition = 0 and currentPosition = 0
so i changed this line on the method to
if (newPosition === currentPosition && newPosition !== 0) return false;
and it works now fine.
Since this does not work
mySwiper.swipeTo(0, 1, false)
you could also force it like
var swiper = new Swiper(
".swiper-container",
slideConfigs
);
swiper.on('beforeInit', function () {
swiper.slideTo(1, 1, false)
swiper.slidePrev(1, false)
})
swiper.init()
And don't forget to add this to your configs
init: false,

Dynamically change the location of the popover depending upon where it displays

I'd like to dynamically change the popover placement (left/right, top/bottom) depending on where the element is located on the screen.
//get_popover_placement(dom_el) returns 'left', 'right', 'top', or 'bottom'
function set_popover(dom_el) {
var the_placement = get_popover_placement(dom_el);
$(dom_el).popover({
offset: 10,
placement: the_placement
}).popover('show');
}
//set the placement on every hover
$('a[data-rel=popover]').hover(function(){
set_popover(this);
}, function(){});
It works the first time, but if the position of the element changes (when the window is resized, for example), the placement is not updated with subsequent calls to set_popover.
I added a little bit of code to get_popover_placement that adds a different color border to the element, depending on the placement. The border color gets updated every time, indicating the code is being called and the calculations are being done correctly, but the placement does not get updated.
It appears as though the placement option can only be set one time. How can I get around this limitation? Is there a variable somewhere that can be cleared to reset popovers?
Try this change, using the .on() function in jQuery to attach an event listener:
Changed this reply by updating Kevin Ansfield's - added code to the placement function.
$('a[data-rel=popover]').popover({
placement: get_popover_placement
});
function get_popover_placement(pop, dom_el) {
var width = window.innerWidth;
if (width<500) return 'bottom';
var left_pos = $(dom_el).offset().left;
if (width - left_pos > 400) return 'right';
return 'left';
}
I just checked the bootstrap source again and realised that functions passed to the placement property get passed arguments. I managed to achieve a similar thing to what you were attempting, try the following and see if it works for you:
$('a[data-rel=popover]').popover({
offset: 10,
placement: get_popover_placement
});
function get_popover_placement(pop, dom_el) {
// your placement function code here
}

make qtip disappear right away

so I want the following behavior out of qtip:
the qtip should show up when I click on the object (I got this working without problem)...but then I want to have it disappear after a few miliseconds without me having to do anything....how would you go about configuring qtip to do this?
i tried
hide: {
when : 'inactive',
delay : 100,
fixed: false
}
but it's not working....
any help would be appreciated...thanks
If you only want the tooltip to flash on screen:
$(".tooltip").qtip({
content: "Test tooltip",
api: {
// As soon as the qtip is fully visible..
onShow: function (event) {
// Keep a reference to the qtip..
that = this;
// After 1ms (to let things settle down)
setTimeout(function () {
// Hide the qtip
that.hide();
}, 1); // change this value to have it stay on screen longer
}
},
show: "mouseover"
});
I know this is an old question but just in case someone passes by, the right way to do it in qTip2 is: (events instead of api)
events: {
show: function(event, api){
var that = this;
setTimeout(function () {
// Hide the qtip
that.hide();
}, 3000); // change this value to have it stay on screen longer
}
}
I think your code is correct, but the delay is causing problems. 100ms is only 0.1 seconds, so maybe the qtip is taking longer than that time to render, in which it won't exist yet when it's told to hide itself (just a guess).
I would increase the delay (you probably want your users to see the tip for a few seconds anyway) and see if that helps. Here's an example that uses 1000ms: http://jsfiddle.net/andrewwhitaker/dVEYq/

Categories

Resources