javascriptwordpresselementor

Javascript not work properly in Loop Grid widget(Elementor Pro)


I have a loop item template, where among other things, there is a button widget (with no click on it, used just for shape and easy to use) that fetches a custom field value from the post. This value is a number between 0-100. The button is accompanied by a script that changes the color of the button based on the value in it.

Now here's the problem: When using this template for the loop grid widget, the script works only for the first post in the list. All other post have standard color buttons that does not depend on the value in it. All other things work fine. My only problem is to let this javascript work for every element in the loop grid widget. I tried to put the script not in the loop item template but in page where the the loop grid widget will be used, but it doesn't work either.

The button has the ID set to 'myButton', and I thought that's where the problem lies, maybe in subsequent elements of the loop grid, the buttons lose that id?

Edit:

I will add some extra info. I can't give more HTML because i'm using mostly elementor to do so. The only code I wrote was the script. But i can give you some example and a step-by-step process that I followed.

Let's say I have 3 posts, which we will call postA, postB, postC.

Each post has a custom field( created via the ACF plugin) which can be different or the same as other posts. This custom field we will call it 'Number' and it is always a value between 0 and 100(integer). postA has the 'Number' set to 12, postB to 99, postC to 72.

My intent is to create, using Elementor, a 'loop item' that shows post name. Under that, the custom field 'Number' inside a circle whose color changes based on the value of 'Number' itself.

Now, since I don't know how to take the value of 'Number' through a code written directly by me, and instead of creating an element with text in the middle in html, modifying it in the form of a circle and with specific color in CSS, I decided to use Elementor's 'Button' widget, which allows me easily to take the value of 'Number' from the current post in which it is located, and also is easy to modify for creating the circle with value inside that I am trying to achieve(of course I removed the possibility to 'click' on the button and any animation, making it a simple static circle).

With that done, what was left for me to do was to create the script that would dynamically change the color of the button. The code I wrote, inserted via Elementor's 'HTML' widget, works fine, but only for the first button it finds, since I'm using the ID that should be unique.

The final intent is in fact to insert on a page, via Elementor's 'Loop Grid' widget,(where the 'Loop Item' created just now is to be selected), a list of all the posts, with their name and their custom field 'number'.

It should therefore come out something like:

enter image description here

The button is NOT an actual button(no click option, no link, nothing happen if clicked), i simply use the widget 'button' of elementor to easly put the circle, edit it and easly get the 'Number' value inside it.

Clearly, the script I wrote only works with the first element, in fact postA has the button where it is inserted, colored red. The other two following, however, have their button where the custom field ‘Number’ is inserted in a generic color (the one set by default in the widget itself) and not like in the image.

    function getColor(value) {
        const colors = {
            0: '#F50000', 1: '#F50000', 2: '#F50000', 3: '#F50000', 4: '#F50000', 5: '#F50000', 6: '#F50000', 7: '#F50000', 8: '#F50000', 9: '#F50000',
            10: '#F50000', 11: '#F50000', 12: '#F50000', 13: '#F50000', 14: '#F50000', 15: '#F50000', 16: '#F50000', 17: '#F50000', 18: '#F50000', 19: '#F50000',
            20: '#F50000', 21: '#F50000', 22: '#F50000', 23: '#F50000', 24: '#F50000', 25: '#F50000', 26: '#F50000', 27: '#F50000', 28: '#F50000', 29: '#F50000',
            30: '#F50000', 31: '#F50000', 32: '#F50000', 33: '#F50000', 34: '#F50000', 35: '#F50000', 36: '#F50000', 37: '#F50000', 38: '#F50000', 39: '#F50000',
            40: '#F50000', 41: '#F50000', 42: '#F00000', 43: '#EB0000', 44: '#E60000', 45: '#E10000', 46: '#DC0000', 47: '#D70000', 48: '#D20000', 49: '#CD0000',
            50: '#C80000', 51: '#C80A00', 52: '#C81400', 53: '#C81E00', 54: '#C82800', 55: '#C83200', 56: '#C83C00', 57: '#C84600', 58: '#C85000', 59: '#C85A00',
            60: '#C86400', 61: '#C86E00', 62: '#C87800', 63: '#C88200', 64: '#C88C00', 65: '#C89600', 66: '#C8A000', 67: '#C8AA00', 68: '#C8B400', 69: '#C8BE00',
            70: '#C8C800', 71: '#BEC800', 72: '#B4C800', 73: '#AAC800', 74: '#A0C800', 75: '#96C800', 76: '#8CC800', 77: '#82C800', 78: '#78C800', 79: '#6EC800',
            80: '#64C800', 81: '#5AC800', 82: '#50C800', 83: '#46C800', 84: '#3CC800', 85: '#32C800', 86: '#28C800', 87: '#1EC800', 88: '#14C800', 89: '#0AC800',
            90: '#00C800', 91: '#00CD00', 92: '#00D200', 93: '#00D700', 94: '#00DC00', 95: '#00E100', 96: '#00E600', 97: '#00EB00', 98: '#00F000', 99: '#00F500',
            100: '#00FA00'
        };
        return colors[value];
    }

    function updateCircle() {
        const button = document.getElementById('myButton');
        const value = parseInt(button.innerText, 10);
        const primaryColor = '#605BE5'; // primary color fixed
        const secondaryColor = getColor(value);
        button.style.backgroundImage = `linear-gradient(to bottom, ${primaryColor}, ${secondaryColor} 80%)`;
    }

    // Constantly update color
    setInterval(updateCircle, 10);
<button id="myButton">1</button>

This is the html code for one button (in the example this is the first, 12 red)

<div class="elementor-element elementor-element-29412fc elementor-align-left elementor-widget elementor-widget-button" data-id="29412fc" data-element_type="widget" data-settings="{&quot;motion_fx_motion_fx_scrolling&quot;:&quot;yes&quot;,&quot;motion_fx_devices&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;]}" data-widget_type="button.default">
            <div class="elementor-widget-container">
                <div class="elementor-button-wrapper">
        <a class="elementor-button elementor-size-md" role="button">
                    <span class="elementor-button-content-wrapper">
                                <span class="elementor-button-text">12</span>
                </span>
                </a>
    </div>
            </div>
            </div>

Solution

  • So when the page updates with more posts, you get more buttons?

    Here is a script that will add a button to every elemento-element based on the value in elementor-button-text

    const updateCircle = () => {
      Array.from(document.querySelectorAll('.elementor-element'))
        .forEach(element => {
          if (element.querySelector('.articleButton')) return; // already has a button
          const val = element.querySelector('.elementor-button-text').textContent.trim();
          element.innerHTML += `<button class="articleButton">${val}</button>`
        })
    
      const buttons = document.querySelectorAll('.articleButton');
      buttons.forEach((button, i) => {
        const value = parseInt(button.textContent, 10);
        const primaryColor = '#605BE5'; // primary color fixed
        const secondaryColor = colors[value]; // find a better calculation depending on number of posts
        button.style.backgroundImage = `linear-gradient(to bottom, ${primaryColor}, ${secondaryColor} 80%)`;
      });
    };
    
    // Constantly update color
    setInterval(updateCircle, 1000);
    
    /* Testing
    const section = document.querySelector('section');
    const alphabet = Array.from({
      length: 26
    }, (_, i) => String.fromCharCode(65 + i));
    
    const rndLetter = (array) => {
      const randomIndex = Math.floor(Math.random() * array.length);
      return array.splice(randomIndex, 1)[0];
    }
    const len = Object.keys(colors).length;
    let tId = setInterval(() => {
      const letter = rndLetter(alphabet);
      if (alphabet.length === 0) {
        clearInterval(tId);
        return;
      }
      section.innerHTML += `<article id="post-${letter}" class="stratum-advanced-posts__post">
        <div class="stratum-advanced-posts__post-wrapper">
        <img src="https://placehold.co/50x80?text=POST ${letter} image" />
          <div class="stratum-advanced-posts__post-thumbnail">
            ${Math.floor(Math.random() * len)}</div>
        </div>
      </article>`
    }, 1000)
    
    */
    .articleButton {
      border-radius: 50%;
      height: 35px;
    }
    
    .elementor-element {
      display: flex;
    }
    <div class="elementor-element elementor-element-29412fc elementor-align-left elementor-widget elementor-widget-button" data-id="29412fc" data-element_type="widget" data-settings="{&quot;motion_fx_motion_fx_scrolling&quot;:&quot;yes&quot;,&quot;motion_fx_devices&quot;:[&quot;desktop&quot;,&quot;tablet&quot;,&quot;mobile&quot;]}"
      data-widget_type="button.default">
      <div class="elementor-widget-container">
        <div class="elementor-button-wrapper">
          <a class="elementor-button elementor-size-md" role="button">
            <span class="elementor-button-content-wrapper">
              <span class="elementor-button-text">12</span>
            </span>
          </a>
        </div>
      </div>
    </div>
    <script>
      const colors = {
        0: '#F50000',
        1: '#F50000',
        2: '#F50000',
        3: '#F50000',
        4: '#F50000',
        5: '#F50000',
        6: '#F50000',
        7: '#F50000',
        8: '#F50000',
        9: '#F50000',
        10: '#F50000',
        11: '#F50000',
        12: '#F50000',
        13: '#F50000',
        14: '#F50000',
        15: '#F50000',
        16: '#F50000',
        17: '#F50000',
        18: '#F50000',
        19: '#F50000',
        20: '#F50000',
        21: '#F50000',
        22: '#F50000',
        23: '#F50000',
        24: '#F50000',
        25: '#F50000',
        26: '#F50000',
        27: '#F50000',
        28: '#F50000',
        29: '#F50000',
        30: '#F50000',
        31: '#F50000',
        32: '#F50000',
        33: '#F50000',
        34: '#F50000',
        35: '#F50000',
        36: '#F50000',
        37: '#F50000',
        38: '#F50000',
        39: '#F50000',
        40: '#F50000',
        41: '#F50000',
        42: '#F00000',
        43: '#EB0000',
        44: '#E60000',
        45: '#E10000',
        46: '#DC0000',
        47: '#D70000',
        48: '#D20000',
        49: '#CD0000',
        50: '#C80000',
        51: '#C80A00',
        52: '#C81400',
        53: '#C81E00',
        54: '#C82800',
        55: '#C83200',
        56: '#C83C00',
        57: '#C84600',
        58: '#C85000',
        59: '#C85A00',
        60: '#C86400',
        61: '#C86E00',
        62: '#C87800',
        63: '#C88200',
        64: '#C88C00',
        65: '#C89600',
        66: '#C8A000',
        67: '#C8AA00',
        68: '#C8B400',
        69: '#C8BE00',
        70: '#C8C800',
        71: '#BEC800',
        72: '#B4C800',
        73: '#AAC800',
        74: '#A0C800',
        75: '#96C800',
        76: '#8CC800',
        77: '#82C800',
        78: '#78C800',
        79: '#6EC800',
        80: '#64C800',
        81: '#5AC800',
        82: '#50C800',
        83: '#46C800',
        84: '#3CC800',
        85: '#32C800',
        86: '#28C800',
        87: '#1EC800',
        88: '#14C800',
        89: '#0AC800',
        90: '#00C800',
        91: '#00CD00',
        92: '#00D200',
        93: '#00D700',
        94: '#00DC00',
        95: '#00E100',
        96: '#00E600',
        97: '#00EB00',
        98: '#00F000',
        99: '#00F500',
        100: '#00FA00'
      };
    </script>