Re-trigger embed code after pagination loading content

Hi,

I’m having issues with custom code within a collection item not running after pagination. I’ve contacted webflow support and they suggest i get help with code that can reload my code snippet after pagination reload. Here’s the reply from support,

"In Webflow, interactions and other JavaScript functions typically work on page load. However, when pagination is used and elements on the page are replaced without reloading it, these functions need to be restarted each time the page content changes.

To address this issue, you’ll need to ensure that the functions within the collection items are restarted whenever the page content changes. This might involve manually triggering these functions again after the pagination operation is completed or finding a way to bind these functions to elements dynamically so that they are applied to new elements loaded via pagination."

The portfolio of Orchestral Music Productions Limited. Showcase of Lincoln Lam’s past projects, including pop songs, film scores, arrangements, custom music etc.

Does any one know how to achieve that? Thanks a lot!


Here is my site Read-Only: Webflow - Orchestral Music Productions Limited

hi, just checking if anyone’s got time to help me out a bit? been stuck for a long time… thanks!

Hey @lincoln! I’m afraid we can not trigger inline scripts at all. You can, however, modify the current script to make it run for each item.

You can use the CMS Load API callback shown below to run the function each time new items are rendered on the page.

window.fsAttributes = window.fsAttributes || [];
window.fsAttributes.push([
  'cmsload',
  (listInstances) => {
    console.log('cmsload Successfully loaded!');

    // The callback passes a `listInstances` array with all the `CMSList` instances on the page.
    const [listInstance] = listInstances;
   
    //Your function declaration goes here

    //Call the function here for items rendered on page load

    // The `renderitems` event runs whenever the list renders items after switching pages.
    listInstance.on('renderitems', (renderedItems) => {
    //Call function here for newly rendered items
    console.log(renderedItems);
    });
  },
]);

I see you are using dynamic fields on the embed, we will need to add these fields to the item and target them with a query selector.

Let me know if you need any help rewriting the code!

hi luis, yes, i do need some help with codes and where to put them. So where should i put that code on my page? Thanks for getting back!!

Hey @lincoln! I can help you with the complete code, that you will need to add to the </body> section of your custom code.

First I need you to add all these dynamic elements to the items as we will need to rewrite this function to iterate through all the items as we can not trigger inline scripts.

The fields can be hidden! I just need the data to make this code work.

hi Luis, thanks for getting back!

Im not quite sure what I need to do exactly. What do you mean by the ‘items’? The dynamic fields are all connected to my collection items.

HI @Support-Luis , the dynamic fields are all pulled from my cms items. So what else am i missing? thanks!

Hey @licoln!

We cannot trigger inline code, which is where we have the elements such as uniqueID, Slug, and TrackLink.

As we can not trigger this code again after rendering more items we need to have these fields within the element, ideally, as text elements so we can run a function on each element.

Something like this

function createWaveSurfer(config) {
  const wavesurfer = WaveSurfer.create({
    container: config.container,
    progressColor: '#ffffff',
    waveColor: '#ffffff',
    barGap: '2',
    barWidth: '1',
    height: '65',
    cursorWidth: '0',
    url: config.tracklink,
    // Add more configuration options as needed
  });

  wavesurfer.on('decode', () => {
    const button = document.querySelector(config.buttonSelector);
    button.onclick = () => {
      // Bottom player
      const globalplaybtn = document.querySelector('#globalplaybtn');
      globalplaybtn.src = 'https://assets-global.website-files.com/61f6c90352d29627cd69a979/661cdf7333f7a2a70dbd9b21_pause.png';

      document.getElementById('globaltracktitle').innerHTML = config.name;
      wavesurferbottom.load(config.tracklink);
      wavesurferbottom.on('decode', () => {
        wavesurferbottom.play();
      });
    };
  });
}

//This will be run on every pagination change
tracks.forEach(track => {
  createWaveSurfer(track);
});

Note that this is just a Chat GPT example of how the function might look like. This is not tested nor the final version!

We can add dynamic fields like this, a hidden div with the fields as text elements.

thanks @Support-Luis , can you give me an example of what I should put inside the text blocks? and where i should put the code above? thanks.

Sorry, im not a coder, and im trying to understand the whole mechanism of fs and webflow… may need more pointers in next steps…

Sure! I’ll try to record a loom later today to show you what I mean by adding the dynamic fields :wink:

thanks! wait for your instructions!

Hi @Support-Luis , I have added those fields within the hidden div block as suggested above. Could you please take a look if im doing it right? If so, shall we continue? Thanks a lot!

Hey @lincoln! can you publish the page with this changes and let me know?

1 Like

@Support-Luis hi its been published. Music Library

Hey @lincoln! I am still not seeing the div added to the published page, are you sure this is the correct live page?

I don’t know if it could be a Webflow bug where a div without a class is not correctly published so we can also try adding something like player_info as a class or something like so.

Hi @Support-Luis , thanks. It doesn’t seem to be able to appear when it’s hidden in the inspector even i gave all of them a class. So i make it visible and change the size to 0 and it can appear in inspector now. So what’s the next step? Thanks!

Screenshot 2024-06-11 at 5.14.12 PM
Screenshot 2024-06-11 at 5.13.49 PM

Thank you @lincoln!

Now this should be copy/paste ready as I tested it multiple times. Great music by the way!

You can replace all of the code inside you </body> tag with this

<script>
  window.fsAttributes = window.fsAttributes || [];
  window.fsAttributes.push([
    'cmsfilter',
    (filterInstances) => {
      console.log('cmsfilter Successfully loaded!');

      const [filterInstance] = filterInstances;
      const { listInstance } = filterInstance;
      const items = listInstance.items;
      const globalPlayBtn = document.querySelector('#globalplaybtn');

      items.forEach((item) => {
        const trackContainerElement = item.element;
        const trackDataContainer = trackContainerElement.querySelector('.hidden_div');

        const uniqueID = trackDataContainer.querySelector('.uniqueid').textContent;
        const slug = trackDataContainer.querySelector('.slug').textContent;
        const trackLink = trackDataContainer.querySelector('.tracklink').textContent;
        const trackName = trackDataContainer.querySelector('.trackname').textContent;

        const trackData = { uniqueID, slug, trackLink, trackName };
        createWaveSurfer(trackData);
      });

      function createWaveSurfer(config) {
        const { uniqueID, slug, trackLink, trackName } = config;

        const wavesurfer = WaveSurfer.create({
          container: `#${slug}`,
          progressColor: '#ffffff',
          waveColor: '#ffffff',
          barGap: 2,
          barWidth: 1,
          height: 65,
          cursorWidth: 0,
          url: trackLink,
          // Add more configuration options as needed
        });

        wavesurfer.on('decode', () => {
          const button = document.querySelector(`#${uniqueID}`);
          button.onclick = () => {
            globalPlayBtn.src =
              'https://assets-global.website-files.com/61f6c90352d29627cd69a979/661cdf7333f7a2a70dbd9b21_pause.png';

            document.getElementById('globaltracktitle').innerHTML = trackName;

            if (window.wavesurferBottom) {
              window.wavesurferBottom.destroy();
            }

            window.wavesurferBottom = WaveSurfer.create({
              container: '#globalwaveform',
              cursorColor: '#4facb3',
              progressColor: '#525252',
              waveColor: '#00eeff',
              barGap: 2,
              barWidth: 1,
              height: 65,
              // Add more configuration options as needed
            });

            window.wavesurferBottom.load(trackLink);
            window.wavesurferBottom.on('decode', () => {
              window.wavesurferBottom.play();
            });

            const globalButton = document.querySelector('#globalbutton');
            globalButton.onclick = () => {
              if (window.wavesurferBottom.isPlaying()) {
                globalPlayBtn.src =
                  'https://assets-global.website-files.com/61f6c90352d29627cd69a979/661cdf745c4247757e19b954_play-buttton.png';
                window.wavesurferBottom.pause();
              } else {
                globalPlayBtn.src =
                  'https://assets-global.website-files.com/61f6c90352d29627cd69a979/661cdf7333f7a2a70dbd9b21_pause.png';
                window.wavesurferBottom.play();
              }
            };

            // Current time & duration
            const formatTime = (seconds) => {
              const minutes = Math.floor(seconds / 60);
              const secondsRemainder = Math.round(seconds) % 60;
              return `${minutes}:${secondsRemainder.toString().padStart(2, '0')}`;
            };

            const timeEl = document.querySelector('#globaltime');
            const durationEl = document.querySelector('#globalduration');

            window.wavesurferBottom.on('decode', (duration) => {
              durationEl.textContent = formatTime(duration);
            });

            window.wavesurferBottom.on('timeupdate', (currentTime) => {
              timeEl.textContent = formatTime(currentTime);
            });
          };
        });

        return wavesurfer;
      }

      filterInstance.listInstance.on('renderitems', (renderedItems) => {
        renderedItems.forEach((item) => {
          const trackContainerElement = item.element;
          const trackDataContainer = trackContainerElement.querySelector('.hidden_div');

          const uniqueID = trackDataContainer.querySelector('.uniqueid').textContent;
          const slug = trackDataContainer.querySelector('.slug').textContent;
          const trackLink = trackDataContainer.querySelector('.tracklink').textContent;
          const trackName = trackDataContainer.querySelector('.trackname').textContent;

          const trackData = { uniqueID, slug, trackLink, trackName };
          createWaveSurfer(trackData);
        });
      });
      filterInstance.listInstance.on('switchpage', (targetPage) => {
        if (window.wavesurferBottom.isPlaying()) {
          globalPlayBtn.src =
            'https://assets-global.website-files.com/61f6c90352d29627cd69a979/661cdf745c4247757e19b954_play-buttton.png';
          window.wavesurferBottom.pause();
        } else {
          console.log('No audio playing');
          window.wavesurferBottom.pause();
        }
      });
    },
  ]);
</script>

Please let me know how it goes!

1 Like

Wow Thanks a lot! it works like magic!

Just wondering if there’s a way for the ‘Global Player’ to not pause and disappear when changing pages or adding filters? If it’s complicated then I will just take it as is. Thanks a lot for your help!