How To Code : "onscroll event -> stop the player"

Hello I’m currently designing my portfolio.

here is the page : [https://julienwidmer.webflow.io/]
After clicking on the title of the first project “shell advance”
a video from vimeo is playing with PLYR
Then if I scroll during play, It goes back to the menu to watch another project but we still hear the player that play in background.
What I want is that in case I’m playing the video, If I scroll with mouse,
it need to stop the player.

here is the actual custom code. everything is working. the only one that doesn’t work is the last code which is not good.

for(let x = 0 ; x < 20 ; x ++){
     // Play on click .titre
    on('#titre-' + (x + 2), 'click', () => { 
    players[x].play();
    });
    // Stop and back to 0 at end 
    players[x].on('ended', function(event) {
    players[x].pause();
    players[x].currentTime = 0;
    });    
    //Stop on return
	  on('#btnreturn' + (x + 2), 'click', () => { 
		players[x].pause();
		players[x].currentTime = 0;
		//console.log('players[x].stop');
		});    
    
  // WIP - stop on scroll (doesn't work)
    on('.player_js', 'onscroll', () => { 
    players[x].pause();
    players[x].currentTime = 0;
    });

here is the page : [https://julienwidmer.webflow.io/home-swiper]
Here is my site Read-Only: https://preview.webflow.com/preview/julienwidmer?utm_medium=preview_link&utm_source=designer&utm_content=julienwidmer&preview=b1c6e4b8e968903cb0a0e7087aa1063b&pageId=61030daf86d4c07d5d4f4d4d&workflow=preview
( don’t forget to select the page Home-swiper to see the good page !! )

hi @sprea if I understand correctly your goal is to stop play vieo that is out of viewport. Here is my advice, when swiper-slider change it will add class swiper-slide-active to current video wrapper. So I presume you can write for each wrapper simple if/else condition to play only video when swiper-slide-active class is added.

hi, Yes, @Stan that’s what I want.
a simple code like I’ve done but with little change in the terms, would not work ?
Your solution should work. But I have no idea how to write this if/else code. Do you have tips?

Hi @sprea when using scroll event-listener you will need to determine when element is in viewport with use of getBoundingClientRect().

You can read this article to know what and how.

Another way is to use Intersection Observer API you can find more about on MDN and find some articles on net about how to

But first revisit you page and fix errors.

Thank you @Stan will check this and learn. To see If I can fix it myself (or not :slight_smile: )

yes about the 2 first error id. I don’t know why it does that error. The code is for each element populate by CMS, but what is strange is that this error happen only to the first cms element and work then, and attribute id for all elements populated in CMS, first element included (it just begin with #titre-2 instead of #titre-1 from the first slide because of the error). I was thinking it doesn’t really mater at this stage, because the id attribute works with a “+1”.
If it’s a serious error, I don’t know what it really change.

Anyway I have a bigger issue with this code that I want to change… But didn’t manage to perfectly attribute unique IDs to elements that iterate in CMS. I’m sure it’s very simple but didn’t found any people getting answers here.
I talk about it there but didn’t get any answer yet… https://discourse.webflow.com/t/dynamically-attribute-unique-ids-to-a-specific-class-name-elements-inside-a-cms-collection/183168

I’ve tried to embed code with this and a CMS " order number" field ,

<script>
var titr = element.getElementsByClassName('titre');
 titr .id = "titre-</order_number_CMS_Field/>";
</script>

but the selector unfortunately doesn’t select . I Don’t understand why…

the only selector that works is unfortunately with .getElementByID:

 
`var titr = document.getElementById('startplay')
 titr .id = "titre-</order_number_CMS_Field/>";`

but this code partially help, because I need then to attribute an ID to the element via Webflow to make it work, but in this case, the last collection element populate in CMS, is still named as before (‘#startplay’) and doesn’t change the last one with this embed code.

So that doesn’t help for my “players” code above (on first post above) which work for every player but then not the last one, because the last one is named differently. #startplay instead of #titre-12

Just begining to investigate, If I can’t resolve it, I will probably ask the help of a dev, when i’ve finish main of what i can still do by myself, with the help of the community.

Hi @sprea

  1. you can add ID programatically with JS (no need set these manually) if no need exact videos lineup

  2. better way to grab element is with use of querySelector no big difference but…

  3. In your 2 examples you are pointing two different things => element vs document

  4. null element mean that is not selected before is called

If you will need help on project you can send me PM and we can talk about my rates.

EDIT: one small hint how to possibly get of these null errors. When JS is applied in embed element you should wrap your JS in listener to wait when all DOM elements are loaded.

document.addEventListener("DOMContentLoaded", () => {
// your code
})
  1. Sure That’s what I did first without any manual ID , but didn’t find a Class selector that work on embed code (I need to name it with a CMS field “number” because this will evolve in a special order that need to be exactly the same as the order of this field )

  2. I tried first with querySelector ! but it didn’t work probably because Jquery doesn’t work on embed code.

3 .yes I know, but this is just a WIP solution, I tried both and inside CMS, both work, it’s just the last one I tried and forget to put it back to element. Anyway this is a completely WIP solution that I will change quickly. neither are the one to keep. because it doesn’t work for the last CMS element, so I don’t want a ID selector because I need to let it blank in the Webflow classic manual ID field. I just want a class selector that work in embed code (so not in Jquery).

  1. yes, but I don’t know why. :slight_smile: (DOM not ready??)

5 . Good to know, Thank You. I’ve contact one already, waiting answers. Will let You know. Still trying by myself on these little thing help me to learn a lot. but anyway I will probably finish to team up with a dev. to optimize it.

no worry, good luck :wink:

thanks, will let you know… :slight_smile:

Will check again this embed code now.

Just seen your EDIT thanks for the tips.
will try again with the listener on top.

Could You confirm my answer at 2). that querySelector can’t work in Embed code because it’s Jquery right ?

in this case, I will try again with getElementsByClassName() with the listener before.

no, it’s is only another selector. You can get more info from your developer or here

Nothing sure for the developper yet. Today I’m still working and learning with webflow community at this moment. (thanking you by the way). That’s also Interesting to learn and understand from my mistake. :slight_smile:

I’ve tried with the DOM, I have no more error for the IDs, but nothing is working anymore with the code inside “before Body” which normally control the player. I’m currently try some test to understand why.

Thanks for your answer, will check and retry QuerySelector, just after these test.

@Stan I’ve done many tests based on your advices.

Adding the DOM line.
I’ve tried adding the DOM in embed Code. If I do this I got no more error visible on the console, but if I do that, then the before body code that I’ve done to control the players write on top post of this topic are no longer working. I mean this no longer work :

for(let x = 0 ; x < 20 ; x ++){
     // Play on click .titre
    on('#titre-' + (x + 2), 'click', () => { 
    players[x].play();
    });
    // Stop and back to 0 at end 
    players[x].on('ended', function(event) {
    players[x].pause();
    players[x].currentTime = 0;
    });    
    //Stop on return
	  on('#btnreturn' + (x + 2), 'click', () => { 
		players[x].pause();
		players[x].currentTime = 0;
		//console.log('players[x].stop');
		});

If I ad the DOM listener line, the first button is now beginning by 1 and not 2 because no error on 1 … I’ve of course change the number on the body code, but anyway that doesn’t work when you add the listener.

I’ved already tried before posting here with querySelector but this selector was not working and put a lot of error, it’s why I’ve worked then with document.getElementById which is the only one directly working (unless the last CMS element that was keeping is original ID) as I want Inside CMS Embed code.
As you told me to do yesterday, I’ve retried again last night by putting this

querySelector()

with

`var titr = document.querySelector('.titre');`
titr .id = "titre-{orderNumberCMSfield}";

that doesn’t work… with or without document.addEventListener("DOMContentLoaded", () => {
is the same , no Id are attributed inside CMS.probably because of the repetition of the command for each collection list.

I’ve also tried :

var titr = document.querySelectorAll('.titre');
titr .id = "titre-{orderNumberCMSfield}";

with or without document.addEventListener("DOMContentLoaded", () => { before
is the same , no Id are attributed.

the only way at this time that works is still with what I’ve already put before

var titr = document.getElementById('startplay')
titr .id = "titre-{orderNumberCMSfield}"

this attribute ID for everything but the last item.

I think it’s document.querySelector is not working because it check the first iteration of the document not the element, and not the closest one. As embed code is inside CMS.

for the other byClassName the code is repeated every time it appears in CMS. so it’s repeated and make conflict I think… it’s why the only selector from these working well is the byID.

I think Inside CMS it need to be a selector that will find only the closest one or put an embed on top a Titre and say to apply ID to the children.(will check how to write that) or make an selectorAll from outside of the CMS collection list to avoid repetition. No?

will check this.

What do you mean with that???

  1. My tip was for Embed element only and doesnt make sense to use it on before body end.

  1. you do not need two DOM load listeners !!! just use one.

When standard selectors aren’t working for you is not because of JS but because you are doing something wrong. But if getElementById works for you just use this, no big deal.

!!! DELETE THESE GAPS !!!
CleanShot 2021-09-11 at 13.29.54

You are overcomplicating things. If you will read article I have posted you should be done by now. Is hard to explain something in JS when you do not understand I’m trying to say.

Sorry

No.
First one was already there. I didn’t add it .
it is there since 10 days.
I was talking to the line to ad in Embed.

I think the problem was because the selector (embed code) was inside the CMS collection list.
asking again and again and again in each embed code slide (collection item).

I’ve found another way, with embed code outside of CMS collection list, that work as espected :

 document.addEventListener("DOMContentLoaded", () => { 

var btret = document.querySelectorAll('.buttonreturn');

for(let x = 0 ; x < 30 ; x ++){
btret[x].id = "btnreturn" + (x + 0);
}
 })

same for the other one. I get the IDs.
and it works with the players.

need to clean but it works from A to Z.

much cleaner code now :clap:

1 Like

HI @sprea I was now checking your code to find BG video. So As you see you have autoplay set to true you can set is to false === 0 to NOT autoplay BG video and start from there.

  1. grab each element wrapper eg. swiper-slide or whatever is good for you
  2. set condition to check if is in viewport
  3. if wrapper in viewport == true grab iframe and set play to true else == false

Note: Be careful what iframe you will work with as you have two iframe element in each 1. BG and 2. video it self

I know that is simple explanation but I hope you can work with it.

Hi @Stan Stan, yes but autoplay=true is completely what I want. so I will not change it. :grinning_face_with_smiling_eyes:

It’s completely normal. On load There is the videos posters (wrapCover) that present extract of the projects, and If you click on the title of one project (when the cursor mouse show a triangle) you get the launch of the proper full video with sound.

I will test soon with many people to check the UX.
if nobody click on the poster to get the proper video , I will probably ad a text or something that appear on the first load to insist.
anyway I want people to see very soon some quick extract during the menu cover. If they click they have the time to check full films.

and for very slow connection will do a code to get fix image posters on menu instead of videos.

In my last input BACKGROUND video will not play at all but ONLY when in viewport. At this time ALL background videos play in loop continuously no mother if they are in viewport or not and this is expensive (compute time) but as you say that is not your problem now.

Now I’m confused as I doesn’t know what you actually need so I’m giving up. I hope that your developer or someone else will understand what you trying to achieve and will be able to write for you code you need as this will be the best and simplest way.
good luck

No no what i am asking on top is :
When the « player » (not the one from the menu « cover » but the full video with audio, inside any project page) is playing, if somebody scroll down or up, It stop this video (and with the help of the actual interaction trigger the cover videos menu come back already, so that we get the menu and face to the next or previous project.) so it stop the actual full video playing inside the project, to stop the sound & pic of this video, that without this code, would continue to play during the menu. That I don’t want.
it is just to stop the full video in case , inside a project, during play, somebody slide up or down, instead of going back to the menu cover with the returnbtn. It need also to stop this video by this way…