0

I have a website with couple of dropdown lists. When a value is selected in one dropdown list, the site runs a javascript code that changes the options in other dropdown lists.

(Example: I select a country in the first list and the dropdown below it is populated with a list of cities from that country).

This isn't my website. I am trying to create a Greasemonkey script that will fill values to these dropdowns. I am able to simulate selection of an option using this jQuery command.

$('select[id="dropdown1"]').val("GBR").trigger('change');

This works fine. It selects the value in the top dropdown. Not in the others however, because they don't yet contain the values I am sending there.

I want the other dropdown lists to be populated according to my selection, but that doesn't happen until my script ends. In other words, the script that runs on the website and populates the dropdown lists waits for my script to end.

What I would like to achieve is to pause my script, allow website scripts to run and then continue my script. In other words, give website scripts priority to execute.

I tried using setTimeout but that didn't work. It even stop changing the top dropdown list value.

setTimeout(function() {
    $('select[id="dropdown1"]').val("GBR").trigger('change');
}, 3000);

Any idea how to pause my script, let others to execute and then continue running my script?

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
Jan Horčička
  • 671
  • 1
  • 11
  • 26
  • How are the options of the other dropdowns are loaded? – dferenc Dec 02 '17 at 21:48
  • You should not put that code in the `setTimeout` callback, but the other, secondary code, which works with the other list. – trincot Dec 02 '17 at 21:49
  • Are you using Greasemonkey 4 on Firefox? – Brock Adams Dec 02 '17 at 22:21
  • @BrockAdams, why did you change the tag when the OP has not confirmed the GM version? – trincot Dec 02 '17 at 22:28
  • @trincot, because the updates are automatic unless the user is savvy. The odds are with me. ;) ... Also, OP seems unresponsive, so wait for answer could be indefinite. – Brock Adams Dec 02 '17 at 22:29
  • The options are loaded from DB via AJAX request. I am not really sure right now, I suppose it will be the newest version. On Chrome. – Jan Horčička Dec 02 '17 at 23:32
  • @BrockAdams, can you explain to me what the "waitForKeyElements" function does? It says that it "detects and handles AJAXed content". I use an identifier and a function, that's pretty self-explanatory. But what does it mean "to detect"? Does it mean that it checks if the element exist? The dropdowns I care about exist on the page all the time ( – Jan Horčička Dec 02 '17 at 23:40
  • If you are using Chrome, then you are not using Greasemonkey. ... If you care about the options, then that's what you tune your WFKE selector for. – Brock Adams Dec 02 '17 at 23:59
  • @BrockAdams So the idea is to use WFKE with the selector for the items I want to select in the later stages (the ones that get loaded after previous selections), is that correct? – Jan Horčička Dec 03 '17 at 00:10
  • You would chain WFKE as shown in the linked answer. – Brock Adams Dec 03 '17 at 00:12

1 Answers1

0

It can work with setTimeout, but you should not put your "GBR" selection in its callback -- you want to execute that part still immediately. Instead put other code there, which will check if the second list has been populated, and if so, to perform whatever action with it that you intended to do.

Here is some some code, where the "existing page" is simulated with some dummy Ajax server which provides some Latin words as response and which are used to populate the second list box:

// Script already on the page -- you can ignore this bit
$("#dropdown1").change(function() {
    $.get("https://jsonplaceholder.typicode.com/posts/" + (this.selectedIndex+1)).then(function (response) {
        $("#dropdown2").empty().append(
            $.map(response.body.split(" "), function (txt) {
                return $("<option>").text(txt)
            })
        );
    });
});

// Your GreaseMonkey script:
$("#dropdown2").empty(); // really empty this, so you can detect when it is populated
$('#dropdown1').val("GBR").trigger('change');
setTimeout(function loop() {
    if ($("#dropdown2>option").length) {
        console.log('change detected');
        return;
    }
    // Keep trying
    setTimeout(loop, 50);
}, 50);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="dropdown1">
    <option>Norway</option>
    <option>Jemen</option>
    <option>Kenya</option>
    <option>GBR</option>
</select>
<select id="dropdown2">
</select>

Note how the GBR value is selected upon page load, and that the console outputs that the change in the second box has been detected. That second bit happens in the setTimeout callback.

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thank you for the code. I will first try the WFKE solution proposed above and if that doesn't work, I will try your solution and let you know how it worked. – Jan Horčička Dec 03 '17 at 14:25