jQuery UI modal form crazy stepping on the pit

I wanted to apply the front-end components to write a form validation page, so I tried jQuery UI

Example of the official website

First, paste the example from the official website:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>jQuery UI Dialog - Modal form</title>
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <link rel="stylesheet" href="/resources/demos/style.css">
    <style>
        label, input { display:block; }
        input.text { margin-bottom:12px; width:95%; padding: .4em; }
        fieldset { padding:0; border:0; margin-top:25px; }
        h1 { font-size: 1.2em; margin: .6em 0; }
        div#users-contain { width: 350px; margin: 20px 0; }
        div#users-contain table { margin: 1em 0; border-collapse: collapse; width: 100%; }
        div#users-contain table td, div#users-contain table th { border: 1px solid #eee; padding: .6em 10px; text-align: left; }
        .ui-dialog .ui-state-error { padding: .3em; }
        .validateTips { border: 1px solid transparent; padding: 0.3em; }
    </style>
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script>
        $( function() {
            var dialog, form,
                // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29
                emailRegex = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
                name = $( "#name" ),
                email = $( "#email" ),
                password = $( "#password" ),
                allFields = $( [] ).add( name ).add( email ).add( password ),
                tips = $( ".validateTips" );

            function updateTips( t ) {
                tips
                    .text( t )
                    .addClass( "ui-state-highlight" );
                setTimeout(function() {
                    tips.removeClass( "ui-state-highlight", 1500 );
                }, 500 );
            }

            function checkLength( o, n, min, max ) {
                if ( o.val().length > max || o.val().length < min ) {
                    o.addClass( "ui-state-error" );
                    updateTips( "Length of " + n + " must be between " +
                        min + " and " + max + "." );
                    return false;
                } else {
                    return true;
                }
            }

            function checkRegexp( o, regexp, n ) {
                if ( !( regexp.test( o.val() ) ) ) {
                    o.addClass( "ui-state-error" );
                    updateTips( n );
                    return false;
                } else {
                    return true;
                }
            }

            function addUser() {
                var valid = true;
                allFields.removeClass( "ui-state-error" );
                valid = valid && checkLength( name, "username", 3, 16 );
                valid = valid && checkLength( email, "email", 6, 80 );
                valid = valid && checkLength( password, "password", 5, 16 );
                valid = valid && checkRegexp( name, /^[a-z]([0-9a-z_\s])+$/i, "Username may consist of a-z, 0-9, underscores, spaces and must begin with a letter." );
                valid = valid && checkRegexp( email, emailRegex, "eg. [email protected]" );
                valid = valid && checkRegexp( password, /^([0-9a-zA-Z])+$/, "Password field only allow : a-z 0-9" );
                if ( valid ) {
                    $( "#users tbody" ).append( "<tr>" +
                        "<td>" + name.val() + "</td>" +
                        "<td>" + email.val() + "</td>" +
                        "<td>" + password.val() + "</td>" +
                        "</tr>" );
                    dialog.dialog( "close" );
                }
                return valid;
                }

            dialog = $( "#dialog-form" ).dialog({
                autoOpen: false,
                height: 400,
                width: 350,
                modal: true,
                buttons: {
                    "Create an account": addUser,
                    Cancel: function() {
                        dialog.dialog( "close" );
                    }
                },
                close: function() {
                    form[ 0 ].reset();
                    allFields.removeClass( "ui-state-error" );
                }
            });

            form = dialog.find( "form" ).on( "submit", function( event ) {
                event.preventDefault();
                addUser();
            });

            $( "#create-user" ).button().on( "click", function() {
                dialog.dialog( "open" );
            });
        });
    </script>
</head>
<body>
<div id="dialog-form" title="Create new user">
    <p class="validateTips">All form fields are required.</p>
    <form>
        <fieldset>
            <label for="name">Name</label>
            <input type="text" name="name" id="name" value="Jane Smith" class="text ui-widget-content ui-corner-all">
            <label for="email">Email</label>
            <input type="text" name="email" id="email" value="[email protected]" class="text ui-widget-content ui-corner-all">
            <label for="password">Password</label>
            <input type="password" name="password" id="password" value="xxxxxxx" class="text ui-widget-content ui-corner-all">
            <!-- Allow form submission with keyboard without duplicating the dialog button -->
            <input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
        </fieldset>
    </form>
</div>

<div id="users-contain" class="ui-widget">
    <h1>Existing Users:</h1>
    <table id="users" class="ui-widget ui-widget-content">
        <thead>
        <tr class="ui-widget-header ">
            <th>Name</th>
            <th>Email</th>
            <th>Password</th>
        </tr>
        </thead>
        <tbody>
        <tr>
            <td>John Doe</td>
            <td>[email protected]</td>
            <td>johndoe1</td>
        </tr>
        </tbody>
    </table>
</div>
<button id="create-user">Create new user</button>
</body>
</html>

Tried it and everything was fine.

From the position of the form DIV

First of all, I see that the CSS is written very thickly, such as the first line:

label, input { display:block; }

The styles of all labels and input labels are directly defined. Seeing that there are 2 DIVs in the body, I want to wrap another layer of divs outside the 2 divs, like this:

<body>
<div id="myui">
    <div id="dialog-form" title="Create new user"></div>
    <div id="users-contain" class="ui-widget"></div>
</div>
</body>

Then add your own div in front of all CSS styles, so that it will not conflict with other styles, such as this:

#myui label, #myui input { display:block; }

Problem: After modification, none of the CSS styles in the modal box are applied. For example, lable and input did not become block-level tags, resulting in no line wrapping
: here, the position of the div with id="dialog-form" has changed, and it ran outside the div with id="myui". The reason for this is that jQuery UI does this, digs out the div with id="dialog-form", and appends it to a position after it comes out, and the default position is the body tag.
Solution: After knowing the reason, it is also possible to modify the writing of css. But there is also a way to make the div with id="dialog-form" still inside the id="myui" as originally thought. Add an appendTo parameter to the dialog to specify the position where the modal box is to be added. If it is not specified before, it is the default (body):

            dialog = $( "#dialog-form" ).dialog({
                appendTo: '#myui',
                autoOpen: false,
                height: 400,
                width: 350,
                modal: true,
                buttons: {
                    "Create an account": addUser,
                    Cancel: function() {
                        dialog.dialog( "close" );
                    }
                },
                close: function() {
                    form[ 0 ].reset();
                    allFields.removeClass( "ui-state-error" );
                }
            });

There are actually 2 submit buttons

Before submitting the form, it is important to know that there are actually 2 buttons that can be used to submit in this example. One of them is hidden.
The submit button written in the form:

            <!-- Allow form submission with keyboard without duplicating the dialog button -->
            <input type="submit" tabindex="-1" style="position:absolute; top:-1000px">

The actual position should be running outside the screen. You can see it by removing the style attribute here. The function of this button is to facilitate us to use the Enter key of the keyboard to operate.
In addition, the buttons generated by jQuery UI for us are generated using dialog = $( "#dialog-form" ).dialog()the buttons attribute in , where you can customize and add more buttons:

                buttons: {
                    "Create an account": addUser,
                    Cancel: function() {
                        dialog.dialog( "close" );
                    }
                },

In addition, the confirmation button here is not submit, but a method that triggers an addUser for form validation. After the verification in addUser is passed, the front-end label will be generated, and a row of data will be added to the front-end, but submit is submitted.

Form could not be submitted

The demo code is a pure front-end implementation. If you want to submit it to the back-end, add the action attribute to the form tag. Then remove the style attribute of the submit button first, and submit it first with submit.
Problem: The backend cannot receive the incoming request
Reason: The frontend blocked the default operation of the submit event, specifically the following sentence

            form = dialog.find( "form" ).on( "submit", function( event ) {
                event.preventDefault();  // 这句的意思就是取消事件的默认操作
                addUser();
            });

Solution: Just comment out the blocked code here.
Now you can use the Enter key to submit, but the confirm button cannot be submitted.

Question 2: The confirmation button is not submit
Reason: This button is bound to addUser, and there is no submit submission in addUser
Solution: Bind the click of the confirmation button to the submit event that triggers the form, so that the effect of the confirmation button is the same as that of submit It's the same, and addUser() must be executed first for verification in submit. dialog = $( "#dialog-form" ).dialog()Change the buttons property in to the following, the parameters of this buttons can support two forms of Object and Array, here I use the form of Array instead:

            buttons: [
                {text: "确认", click: function () {
                        form.submit();
                    }},
                {text: "取消", click: function () {
                        dialog.dialog('close');
                    }
                }
            ],

The requested form content is empty

Now the backend can receive requests, but all it receives are empty requests with no value.
Problem: The request is received in the backend, but the requested value is all null
Reason: The frontend empties the content of the form before sending the submit request. There is a close attribute at dialog = $( "#dialog-form" ).dialog()the end of the , and the value is a method:

                close: function() {
                    form[ 0 ].reset();
                    allFields.removeClass( "ui-state-error" );
                }

The close attribute is the content to be executed when the dialog box is closed, which empties the content of the form form.
The specific steps are that the submit event will first trigger addUser() for form validation. In addUser(), checkLength() is used to verify the length first, and then checkRegexp() is used for regular verification. If validation fails, it will return false to organize the event after that. If the verification is passed, the operation of closing the modal box will be executed first:

                    dialog.dialog( "close" );

Here, the modal box is closed, and then true is returned, and then the action of submit is executed. But when the modal is closed, the data is cleared. What the service receives is the request from the empty form that has been emptied, and after passing the front-end data validation.
Solution: It should be possible not to close the modal box first, and then close it after the submit is submitted. However, it is not convenient to implement. The form clearing function is still useful, but as long as it is cleared before the next opening. Here you can replace the original close method with an open method.
Another pit: there is a create method on the page of the official website, and I originally wanted to use this. But I found it was useless, and then I went to the source code to find it (jquery-ui.js):

$.widget( "ui.dialog", {
    version: "1.12.1",
    options: {
        appendTo: "body",
        autoOpen: true,
        buttons: [],
        classes: {
            "ui-dialog": "ui-corner-all",
            "ui-dialog-titlebar": "ui-corner-all"
        },
        closeOnEscape: true,
        closeText: "Close",
        draggable: true,
        hide: null,
        height: "auto",
        maxHeight: null,
        maxWidth: null,
        minHeight: 150,
        minWidth: 150,
        modal: false,
        position: {
            my: "center",
            at: "center",
            of: window,
            collision: "fit",

            // Ensure the titlebar is always visible
            using: function( pos ) {
                var topOffset = $( this ).css( pos ).offset().top;
                if ( topOffset < 0 ) {
                    $( this ).css( "top", pos.top - topOffset );
                }
            }
        },
        resizable: true,
        show: null,
        title: null,
        width: 300,

        // Callbacks
        beforeClose: null,
        close: null,
        drag: null,
        dragStart: null,
        dragStop: null,
        focus: null,
        open: null,
        resize: null,
        resizeStart: null,
        resizeStop: null
    },

The above Callbacks should be all the methods, and there is no create. Then try to open.

Optimization - Resize modal box

It is still the function that generates the modal box. dialog = $( "#dialog-form" ).dialog()The height and width properties in it can set the default size of the modal box
. Here, the modal box may have a scroll wheel
. Reason: modal box id="dialog-form" in this div There is this style overflow: auto , so the scroll bar will appear on overflow.
Solution: It should be enough to overwrite the overflow style, but the fundamental problem is overflow. The label that caused the overflow here is the input label in the form. The style is this:

input.text { margin-bottom:12px; width:95%; padding: .4em; }

Here I adjusted the width of width just fine.

Optimization - directly hide the modal box

This is not the case in the example, but when I use it, the modal box will be displayed first when the page is loaded, and the modal box will be hidden after the loading is complete.
Problem: When the page is loaded, there will be a modal box for a moment
Reason: Because I put the position of the js code at the end, the code of the label of the modal box will be displayed when it is read, and the js code will be read. The
solution will be hidden only when the time comes: the js dialog = $( "#dialog-form" ).dialog()method mentioned above. But I used another method and added this class to the div tag of my modal:

<div class="ui-helper-hidden" id="dialog-form" title="Create new user">

In jquery-ui.css, the class looks like this:

.ui-helper-hidden {
    display: none;
}

It is simply hidden, and it can still be displayed after trying it.

revised version

Replacing the template language part, the modified version I use is as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <style>
        #jqui-dialog label, #jqui-dialog input { display:block; }
        #jqui-dialog form input { margin-bottom:12px; width: 92%; padding: .4em; }
        #jqui-dialog fieldset { padding:0; border:0; margin-top:25px; }
        #jqui-dialog h1 { font-size: 1.2em; margin: .6em 0; }
        #jqui-dialog div#users-contain { width: 350px; margin: 20px 0; }
        #jqui-dialog div#users-contain table { margin: 1em 0; border-collapse: collapse; width: 100%; }
        #jqui-dialog div#users-contain table td, #jqui-dialog div#users-contain table th {
            border: 1px solid #eee;
            padding: .6em 10px;
            text-align: left;
        }
        #jqui-dialog .ui-dialog .ui-state-error { padding: .3em; }
        #jqui-dialog .validateTips { border: 1px solid transparent; padding: 0.3em; }
    </style>
</head>
<body>
<div id="jqui-dialog">
    <div class="ui-helper-hidden" id="dialog-form" title="添加新用户组">
        <p class="validateTips">请填写要新建的组的名称</p>
        <form action="." method="post">
            <fieldset>
                <label for="group_name">组名称</label>
                <input type="text" name="group_name" id="group_name" class="text ui-widget-content ui-corner-all">
                <label for="comments">备注</label>
                <input type="text" name="comments" id="comments" class="text ui-widget-content ui-corner-all">
                <!-- Allow form submission with keyboard without duplicating the dialog button -->
                <input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
            </fieldset>
        </form>
    </div>

    <div id="users-contain" class="ui-widget">
        <h1>用户组列表:</h1>
        <button id="create-user">添加新用户组</button>
        <table id="users" class="ui-widget ui-widget-content">
            <thead>
            <tr class="ui-widget-header ">
                <th>id</th>
                <th>群组名</th>
                <th>备注</th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td>1</td>
                <td>测试一</td>
                <td>test1</td>
            </tr>
            <tr>
                <td>2</td>
                <td>测试2</td>
                <td>test2</td>
            </tr>
            <tr>
                <td>3</td>
                <td>测试三</td>
                <td>test3</td>
            </tr>
            </tbody>
        </table>
    </div>
</div>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(function () {
    var dialog, form,
        group_name = $('#group_name'),
        comments = $('#comments'),
        allFields = $([]).add(group_name).add(comments),
        tips_msg = null,
        tips = $('.validateTips');

    // 长度验证
    function checkLength(o, n, min, max) {
        if (o.val().length > max || o.val().length < min) {
            o.addClass("ui-state-error");
            updateTips(n + "的长度必须在" +
                min + "与" + max + "之间。");
            return false
        } else {
            return true
        }
    }

    // 正则验证
    function checkRegexp(o, regexp, n) {
        if (!(regexp.test(o.val()))) {
            o.addClass("ui-state-error");
            updateTips(n);
            return false
        } else {
            return true
        }
    }

    // 显示错误信息
    function updateTips(t) {
        tips_msg = tips_msg || tips.text();
        tips.text(t).addClass("ui-state-highlight");
        setTimeout(function () {
            tips.removeClass("ui-state-highlight", 1500);
        }, 500);
    }

    function addUser() {
        var valid = true;
        allFields.removeClass("ui-state-error");
        valid = valid && checkLength(group_name, "组名称", 3, 32);
        valid = valid && checkLength(comments, "备注", 0, 64);
        valid = valid && checkRegexp(group_name, /^[^0-9]/, "组名称不能以数字开头");
        if (valid) {
            $( "#users tbody" ).append( "<tr>" +
                "<td>" + 'x' + "</td>" +
                "<td>" + group_name.val() + "</td>" +
                "<td>" + comments.val() + "</td>" +
                "</tr>" );
            dialog.dialog('close');
        }
        return valid
    }

    dialog = $("#dialog-form").dialog({
        appendTo: '#jqui-dialog',
        autoOpen: false,
        height: 380,
        width: 300,
        modal: true,
        buttons: [
            {text: "提交", click: function () {
                    form.submit();
                }},
            {text: "取消", click: function () {
                    dialog.dialog('close');
                }
            }
        ],
        open: function() {
            form[ 0 ].reset();
            allFields.removeClass( "ui-state-error" );
            tips_msg && tips.text(tips_msg);
        }
    });

    form = dialog.find("form").on("submit", function(event) {
        event.preventDefault();
        addUser();
    });

    $("#create-user").button().on("click", function() {
        dialog.dialog( "open" );
    });
})
</script>
</body>
</html>

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324934048&siteId=291194637