PATCH 请求不适用于模糊,而适用于按键

PATCH request does not work on blur, while does on keydown

我正在尝试创建一个内嵌编辑器,它将支持点击编辑和保存 enter/blur。环境包括 PHP v5.6、jQuery v3.1、Laravel v5.2 和 MySQL.

问题是,虽然使用 enter 保存有效,但使用 blur 保存无效。

Laravel DB:listen 保存输入:

2016-08-10 12:01:45: select * from `user` where `user`.`id` = '15' limit 1
2016-08-10 12:01:45: update `user` set `name` = '22222', `updated_at` = '2016-08-10 12:01:45' where `id` = '15'

Laravel DB:listen 以节省模糊,请注意根本没有 "update" 查询:

2016-08-10 11:21:53: select * from `user` where `user`.`id` = '15' limit 1

模糊似乎没有检测到 <input> 文本已更改。我该如何解决?

inline-edit.js:

var edit = $(".inline-edit");

edit.click(function() {
    $('.ajax').html($('.ajax input').val());
    $('.ajax').removeClass('ajax');
    $(this).addClass('ajax');
    $OLDVAL = $.trim($(this).text());
    $(this).html('<input id="inline-editbox" type="text" value="' + $OLDVAL + '">');
    // focus and move cursor to the end of the editbox
    var inline_editbox = $('#inline-editbox');
    inline_editbox.focus();
    var editbox_value = inline_editbox.val();
    inline_editbox.val('');
    inline_editbox.val(editbox_value);
    // 
    inline_editbox.blur(function(event) {
        var formData = {
            tag: $(this).attr('id'),
            value: $('.ajax input').val(),
        };
        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
            },
            type: "PATCH",
            data: formData,
            dataType: 'json',
            success: function(data) {
                $('.ajax').html($('.ajax input').val());
                $('.ajax').removeClass('ajax');
            },
            error: function(xhr, status, error) {
                console.warn(xhr.responseText);
                alert(error);
            }
        });
    });
});

edit.keydown(function(event) {
    if (event.keyCode == 13) {
        var formData = {
            tag: $(this).attr('id'),
            value: $('.ajax input').val(),
        };
        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
            },
            type: "PATCH",
            data: formData,
            dataType: 'json',
            success: function(data) {
                $('.ajax').html($('.ajax input').val());
                $('.ajax').removeClass('ajax');
            },
            error: function(xhr, status, error) {
                console.warn(xhr.responseText);
                alert(error);
            }
        });
    }
});

Laravel 的一部分 route.php:

Route::patch ('user/{id}',      ['as'=>'user.patch',  'uses'=>'UserController@update_ajax']);

Laravel 的一部分 UserController.php:

function update_ajax($id, UserCreateFormRequest $request)
{
    $user = User::findOrFail($id);
    $tag  = $request->get('tag');
    if( $tag == 'name') {
        $user->update([
            'name'        =>    $request->get('value')
        ]);
    }

    if( $tag == 'email') {
        $user->update([
            'email'       =>    $request->get('value')
        ]);
    }

    if( $tag == 'isRegistered') {
        $user->update([
            'isRegistered'=>    $request->get('value')
        ]);
    }

    return response()->json([
        'status' => 'success',
        'msg' => 'Data created successfully',
    ]);
}

您的主要问题似乎是您在错误的元素上(在 .inline-editbox 而不是 <input> 上收听了 keydown 事件。

但是,您的代码中也有很多重复和不必要的步骤,因此我重写了它以使其更清晰。

以下:

  • 有一个单独的函数来执行 Ajax 调用(这使得 Ajax 调用和其余代码更容易理解,更重要的是,更容易测试)
  • 使用 jQuery 的 XHR 承诺实现应用程序逻辑和 Ajax 逻辑的分离
  • 通过.trigger()利用jQuery自定义事件,以便将数据上传到服务器集中在一个地方
  • 当服务器更新失败时恢复原始值(您可以实现其他错误行为)
  • 值未更改时不向服务器发送更新
  • 正确处理 HTML 特殊字符(引号、尖括号)(您的版本在这方面存在错误)

完整代码:

function patchUser(params) {
    return $.ajax({
        url: 'user/...',
        headers: {
            'X-CSRF-TOKEN': $('meta[name="_token"]').attr('content')
        },
        type: "PATCH",
        data: JSON.stringify(params),
        contentType: "application/json"
    }).fail(function(xhr, status, error) {
        console.warn(xhr.responseText);
        alert(error);
    });
}

$(".inline-edit").click(function () {
    var $inlineEdit = $(this),
        curentValue = $.trim($inlineEdit.text());

    $inlineEdit.empty().addClass('ajax');
    $('<input>')
        .val(curentValue)
        .appendTo($inlineEdit)
        .on("blur", function () {
            $(this).trigger("contentchange");
        })
        .on("keydown", function (e) {
            if (e.keyCode == 13) $(this).trigger("contentchange");
        })
        .on("contentchange", function () {
            var newValue = $(this).val();
            if (newValue === curentValue) {
                $inlineEdit
                    .text(curentValue)
                    .removeClass('ajax');
            } else {
                patchUser({
                    tag: $inlineEdit.attr('id'),
                    value: newValue
                }).done(function (data) {
                    $inlineEdit.text(data);
                }).fail(function () {
                    $inlineEdit.text(curentValue);
                }).always(function () {
                    $inlineEdit.removeClass('ajax');
                });
            }
        })
        .focus();
});

实时样本

点击运行进行演示。我在这里用模型替换了 patchUser()

function patchUser(params) {
    var result = $.Deferred();
    result.resolve("Value saved: (" + params.value + ")");
    return result.promise();
}

$(".inline-edit").click(function () {
    var $inlineEdit = $(this),
        curentValue = $.trim($inlineEdit.text());

    $inlineEdit.empty().addClass('ajax');
    $('<input>')
        .val(curentValue)
        .appendTo($inlineEdit)
        .on("blur", function () {
            $(this).trigger("contentchange");
        })
        .on("keydown", function (e) {
            if (e.keyCode == 13) $(this).trigger("contentchange");
        })
        .on("contentchange", function () {
            var newValue = $(this).val();
            if (newValue === curentValue) {
                $inlineEdit
                    .text(curentValue)
                    .removeClass('ajax');
            } else {
                patchUser({
                    tag: $inlineEdit.attr('id'),
                    value: newValue
                }).done(function (data) {
                    $inlineEdit.text(data);
                }).fail(function () {
                    $inlineEdit.text(curentValue);
                }).always(function () {
                    $inlineEdit.removeClass('ajax');
                });
            }
        })
        .focus();
});
.inline-edit > input {
  width: 100%;
}
.ajax {
  border: 1px solid green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="inline-edit" id="name">User Name</div>
<div class="inline-edit" id="email">User Email</div>
<div class="inline-edit" id="isRegistered">User IsRegistered</div>