5

I regularly use a web app from Invisalign® to set up orthodontic cases. I use Keyboard Maestro to make keyboard shortcuts within the app by activating JavaScript.

An example of the JavaScript triggered by keyboard maestro:

document.getElementById('myButton').click();

The web app was recently updated and there is no longer a button ID. Thus, the getElementByID is no longer functioning.

I have tried the following but it does not work:

document.getElementByClass('myClass').click();

(I have tried c01143 and c0012)

An example of the HTML for the page is:

<div class='c0012'>
        <button type="button" tabindex="-1" data-qa-name="lower" data-qa-toggled="false" class="c0180 c01149 c01151">
            <div class="c01143">
                <svg class="c0189 c0191" viewBox="0 0 24 24"><path d="M2,13 L22,13 L22,16 L2,16 L2,13 Z M8,8 L16,8 L16,11 L8,11 L8,8 Z"></path></svg>
            </div>
        <span class="c01142">Lower</span>
    </button>
</div>

I have also tried:

document.getElementBydata-qa-name('lower').click();

That also doesn't work. Hopefully someone can help out with what might be a very simple solution. Although I know some HTML and CSS my JavaScript is almost nonexistent.

esqew
  • 42,425
  • 27
  • 92
  • 132
Sage
  • 49
  • 3
  • How about document.getElementsByClassName('c0180 c01149 c01151')[0].click(); https://developer.mozilla.org/fr/docs/Web/API/Document/getElementsByClassName – Ole EH Dufour Oct 06 '20 at 19:53
  • 3
    You may want to be careful about automating these kinds of things -- check their Terms of Service to be sure it's allowed. There may be a reason they redesigned their site to eliminated IDs... – Heretic Monkey Oct 06 '20 at 19:57

2 Answers2

5

The non-descriptive class names (e.g., c0012, c01143) strongly indicate that, somewhere in the site's stack, the HTML/CSS/JS is being dynamically compiled/generated. As such, you should expect that these identifiers could change drastically and quite frequently & you shouldn't rely on them in your snippet.


Method #1 - document.querySelector() using data-qa-name

You can use the document.querySelector() method to identify based on the button tag, the button type value, as well as the custom data-qa-name attribute. The following demonstrates that this method works to identify the element without relying on the class name or the (no longer-existent) ID value:

(() => {
  console.log(document.querySelector("button[type='button'][data-qa-name='lower']"));
})();
<div class='c0012'>
  <button type="button" tabindex="-1" data-qa-name="lower" data-qa-toggled="false" class="c0180 c01149 c01151">
            <div class="c01143">
                <svg class="c0189 c0191" viewBox="0 0 24 24"><path d="M2,13 L22,13 L22,16 L2,16 L2,13 Z M8,8 L16,8 L16,11 L8,11 L8,8 Z"></path></svg>
            </div>
        <span class="c01142">Lower</span>
    </button>
</div>

You would lift and shift the above by simply calling click() on the identified element, as you had previously:

document.querySelector("button[type='button'][data-qa-name='lower']").click();

Method #2 - document.querySelectorAll(), filtered using .innerText value

While from what you've posted there isn't any strong indication that this data-qa-name attribute would change in either name or value, you can also target the element based on its innerText value similar to the following:

[...document.querySelectorAll("button[type='button']")].find(function (ele) {return ele.innerText === "Lower"})).click();

The following snippet, while it appears succinct, performs the following steps:

  1. Enumerates all button elements with an attribute type of button into an Array structure.
  2. Finds and returns the first element in the array that has an innerText property equal to the string Lower.
  3. Executes the click() method on the identified button.

The only scenario in which this particular snippet wouldn't work to your requirements would be if there are buttons appearing somewhere in the DOM tree before the intended button element that also have an innerText property equal to the string "Lower". You'll have to perform a small amount of testing to confirm which of these snippets will work most consistently in your scenario.


Further reading

Considering your self-professed limited understanding of JavaScript, you may wish to consult the following MDN documentation pages to get a better grasp on the methods and linguistic conventions leveraged above:

esqew
  • 42,425
  • 27
  • 92
  • 132
  • Thank you so much esqew. I just wrapped up my day with patients and tried Method 1. It worked like a charm. I am going to look at method 2 and do some of the suggested further reading. A sa simple orthodontist, it's fun to venture out of my bubble and learn something new. – Sage Oct 07 '20 at 04:55
0

With document.querySelector() you can use CSS style selectors to target an element. In the example below it select the first button inside the element with the .c0012 class.

document.querySelector('.c0012 button').click();
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32
  • 2
    While technically correct for the HTML snippet posted, it's likely these classes are dynamically-generated and would change frequently. – esqew Oct 06 '20 at 19:59