0

http://info.academyart.edu/programs?&pmcode=PMDIR

On this page, when you choose any option from "Current level of education" select, an new select is shown below ("Program of interest").

I'm trying to change it's value via my chrome extension like this:

var evt = document.createEvent("HTMLEvents");
var program = document.getElementById('Program');
program.selectedIndex = 1;
evt.initEvent("change", true, true);
program.dispatchEvent(evt);

but it won't change. I tried also with this:

var program = document.getElementById('Program');
program.selectedIndex = 1;

but result is the same.

In my code I first select an value in "current level of education" selectbox, if that matters. So, I can change value in any other select on that page, but I can't change it on this one.

What could be the problem?

13
  • That <select> doesn't have any options other than the title until after the user selects the education level. Then all the options get added by Javascript. I suspect your extension is running before the options get added. Commented Jan 22, 2016 at 2:42
  • How can I "wait" for Javascript in my chrome extension to add options to this select, and then select one of them? Commented Jan 22, 2016 at 2:52
  • I'm not sure. Maybe you should run your code in the change event listener for the education dropdown, after the page's own change listener runs. Commented Jan 22, 2016 at 2:54
  • I try with this, but no result. It prints "lol" to the console though, as a confirmation that change event is registered.. var educationLevel = document.getElementById('educationLevel'); educationLevel.addEventListener("change", function() { var program = document.getElementById('Program'); program.selectedIndex = 1; console.log("lol"); }); educationLevel.selectedIndex = 1; Commented Jan 22, 2016 at 3:07
  • 1
    So your listener is running before the one on the page that adds the options. Like I said before, I don't know how to make sure yours runs after that one. Commented Jan 22, 2016 at 3:38

2 Answers 2

1

Dispatching events is only useful when something listens to them. The element in question (#educationLevel) listens to focus, change, and blur events.

The easiest way to create events is with an Event constructor.

function dispatch(el, evType) {
    el.dispatchEvent(new Event(evType));
}

var level = document.getElementById('educationLevel');
dispatch(level, 'focus');
level.selectedIndex = 1;
dispatch(level, 'change');
dispatch(level, 'blur');

However, #Program only listens to focus and blur so you don't need to dispatch the change event.

The actual problem: #Program is empty on load and only gets populated after change on #educationLevel fires. Thus you need to apply a mutation observer on it:

function initMO(root, callback) {
    var MO = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MO(function(mutations) {
        observer.disconnect();
        mutations.forEach(function(mutation){
            callback(mutation.target);
        });
        observe(); // comment this out to run only once
    });
    var opts = { childList: true, subtree: true };
    var observe = function() {
        observer.takeRecords();
        observer.observe(root, opts);
    };
    observe();
}

full solution:

function dispatch(el, evType) {
    el.dispatchEvent(new Event(evType));
}
function addMO(root, callback) {
    var MO = window.MutationObserver || window.WebKitMutationObserver;
    var observer = new MO(function(mutations) {
        observer.disconnect();
        mutations.forEach(function(mutation){
            callback(mutation.target);
        });
        observe(); // comment this out to run only once
    });
    var opts = { childList: true, subtree: true };
    var observe = function() {
        observer.takeRecords();
        observer.observe(root, opts);
    };
    observe();
}

var level = document.getElementById('educationLevel');
dispatch(level, 'focus');
level.selectedIndex = 1;
dispatch(level, 'change');
dispatch(level, 'blur');

var program = document.getElementById('Program');
addMO(program, function() {
    program.selectedIndex = 1;
});
Sign up to request clarification or add additional context in comments.

2 Comments

It doesn't get selected neither that way.. If I insert console.log(program.options.length); after dispatch(program, 'focus'); it outputs 0
@kecman you replied before I finalized the solution. Reread the answer.
0

When you load the page, your content script is injected and you can view from F12 tool, at that time #Program is hidden with only one option. So after the rest options showing, you content script will not be injected and executed again, that's the root cause.

You should try executing

program.selectedIndex = 1;

after the hidden options show, for example, you can declare a browserActionListener in your background script and do messaging communication when click that, then you can make sure above code be executed in an environment that the rest options can be accessed.

1 Comment

I understand first part of your answer, I came to that conclusion myself, but I don't really understand second one. My intention is to fill whole form with my extension, so there won't be any click event on form.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.