简体   繁体   English

如何触发Ajax请求以填写表单并等待DOM更改?

[英]How to trigger Ajax Request for filling a Form out and wait until DOM changes?

I am going to fill out a Form using JQuery through PhantomJS. 我将通过PhantomJS使用JQuery填写表单

I have following script for doing that: 我有以下脚本可以做到这一点:

var page = require('webpage').create();

page.open('http://demo.opencart.com/index.php?route=account/register', function() {
    fillTheForm();
    phantom.exit();
});

function fillTheForm () {

    page.evaluate(function() {

        var selectTags = new Array();
        selectTags = document.getElementsByTagName('select');
        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');

        $(selectTags[1]).val('610');
    });         
    page.render('form.png');
};

after running this script, I got following message inside the console! 运行此脚本后,我在控制台内收到以下消息!

Alert, JavaScript error 警报,JavaScript错误

Also, the picture that I have, after trying to fill the Form out, tells me that the existing values for the second Select box have not changed yet and then PhantomJS could not assign the value to the second field. 另外,在尝试填写表单后,我所拥有的图片告诉我第二个“选择”框的现有值尚未更改,然后PhantomJS无法将值分配给第二个字段。

Can someone please help me to solve this problem? 有人可以帮我解决这个问题吗? How can I fill out this two fields using JQuery and PhantomJS? 如何使用JQuery和PhantomJS填写这两个字段?

This is the chained selects problem. 这是连锁选择问题。 The second one is dependent on the first one and is populated via AJAX. 第二个依赖于第一个,并通过AJAX填充。 This means that it is asynchronous. 这意味着它是异步的。 You have to wait before you can set the second value. 您必须等待,然后才能设置第二个值。 In PhantomJS this is also problematic, because you have two contexts (page context and phantom context) that have do be "synchronized". 在PhantomJS中,这也是有问题的,因为您有两个上下文(页面上下文和幻像上下文)确实是“同步的”。

For example you can use 例如,您可以使用

function fillTheForm () {
    page.evaluate(function() {
        var selectTags = document.getElementsByTagName('select');
        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');
    });
    setTimeout(function(){
        page.evaluate(function() {
            var selectTags = document.getElementsByTagName('select');
            $(selectTags[1]).val('610');
        });
        page.render('form.png');
        phantom.exit(); // this has to be inside, because everything is asynchronous now
    }, 3000); // assuming 3 seconds are enough time for the request
};

A better and more robust way would be to use waitFor from the examples , because it is finished as soon as the data is available. 一种更好,更可靠的方法是使用示例中的waitFor ,因为一旦数据可用,它就会完成。 Here I have some indicators when the second select is reloaded: 这里有一些重新加载第二选择的指示器:

var page = require('webpage').create();

page.open('http://demo.opencart.com/index.php?route=account/register', function() {
    fillTheForm(function(){
        page.render('form.png');
        phantom.exit();
    });
});

function fillTheForm(done) {
    page.evaluate(function() {
        var selectTags = document.getElementsByTagName('select');

        // custom indicators, perhaps something more elaborate is needed for general selects
        // in this case it is ok
        window._chainedSelectChildrenLength = selectTags[1].children.length;
        window._chainedSelectFirstChildText = selectTags[1].children[0].innerText;

        $(selectTags[0]).val("38");
        $(selectTags[0]).trigger('change');
    });
    waitFor(function testFx(){
        return page.evaluate(function() {
            var selectTags = document.getElementsByTagName('select');
            // use indicators
            return window._chainedSelectChildrenLength !== selectTags[1].children.length ||
                window._chainedSelectFirstChildText !== selectTags[1].children[0].innerText;
        });
    }, function onReady(){
        page.evaluate(function(){
            // continue
            var selectTags = document.getElementsByTagName('select');
            $(selectTags[1]).val('610');
        });
        done();
    }, 5000); // 3 seconds is the default
};

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function() {
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if(!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM