Laravel & ajax: 如何以简化的方式更新多个表单输入

Laravel & ajax: How to update several form inputs in a simplified way

我有一个表单,用户可以在其中更新他的详细信息。此更新是通过使用 jQuery focusout 函数和 Ajax 更新数据库来完成的。

在这个例子中,我有三个文本输入。我已经测试了第一个输入,当用户转到下一个输入时它会更新。更新该输入时会出现加载程序图标。

对于第一个输入,我创建了一个控制器及其相应的 JQuery 代码。

但是,如果我有 10 个输入的表单,我将不得不这样做 10 次。我的问题是:我该如何简化这个?所以我只需要编码一次。

表格如下:

<form role="form" class="form-horizontal" action="{{URL::route('user-edit-profile-post2')}}" method="post" id="formedit2">
    <!---------------------------SECCIÓN USUARIOS---------------------->
    <!-----Nombre de pila---------->
    <div class="form-group @if ($errors->has('nombre_pila')) has-error @endif">
        <label for="nombre_pila" class="col-sm-2 control-label">Nombre(s) de pila:</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="nombre_pila" name="nombre_pila" maxlength="45" value="@if(Input::old('nombre_pila')){{e(Input::old('nombre_pila'))}}@elseif(isset($nombrepila)){{$nombrepila}}@endif">
        </div>    
    @if($errors->has('nombre_pila'))
        <p class="help-block">{{$errors->first('nombre_pila')}}</p>
    @endif
    </div><!-- ----------fin nombre de pila ------------ -->

    <div class="form-group @if ($errors->has('ap_paterno')) has-error @endif"><!--apellido paterno-->
        <label for="ap_paterno" class="col-sm-2 control-label">Apellido paterno:</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="ap_paterno" name="ap_paterno" maxlength="45" value="{{ (Input::old('ap_paterno') ? e(Input::old('ap_paterno')) : (isset($ap_paterno) ? $ap_paterno : '')) }}"><!--Referencias: 
        </div>
    @if($errors->has('ap_paterno'))
        <p class="help-block">{{$errors->first('ap_paterno')}}</p>
    @endif    
    </div><!-- ----------fin de apellido paterno ------------ -->

    <div class="form-group @if ($errors->has('ap_materno')) has-error @endif"><!--apellido materno-->
        <label for="ap_materno" class="col-sm-2 control-label">Apellido materno:</label>
        <div class="col-sm-6">
            <input type="text" class="form-control" id="ap_materno" name="ap_materno" maxlength="45" value="@if(Input::old('ap_materno')){{e(Input::old('ap_materno'))}}@elseif(isset($ap_materno)){{$ap_materno}}@endif">
        </div>
    @if($errors->has('ap_materno'))
        <p class="help-block">{{$errors->first('ap_materno')}}</p>
    @endif    
    </div><!-- ----------fin de apellido paterno ------------ -->

    <!------------------GUARDAR--------------------- -->
    <div class="form-group"><!--Botón de guardar-->
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" class="btn btn-success">Guardar</button>
        </div>
    </div><!--Fin del botón de guardar-->
    <!--------------Fin de GUARDAR ---------------->
    <!--TOKEN-->
    {{ Form::token() }}
</form>

在表格下方,我有这个 JQuery 代码:

<script type="text/javascript">
    $('#nombre_pila').on('focusout',function(){
        var editform = $('#formedit2').serializeArray();
        var url = $("#formedit2").attr('action');//con esto se llama al controlador correspondiente!
        $('#nombre_pila').addClass('loadinggif');
        $.post(url, editform, function(data,status){
            $('#nombre_pila').removeClass('loadinggif');
            //alert(data);
            if(data=='fail'){
                alert('No se pudo actualizar el campo. Status:' + status);
            }else if(data=='success'){
                alert('Dato actualizado exitosamente! Status: ' + status);
            }else if(status=='timeout'){
                alert('El tiempo de espera se ha agotado. Recargue la página.');
            }
        });
    });
</script>

控制器是:

public function postEditProfile2(){
    //save data and send to form page or display a success message
    //instanciando al usuario actual:
    $id_user=Auth::user()->id;
    $usuario=User::find($id_user);
    $nombre_pila=Input::get('nombre_pila');
    //preparando el dato para guardarlo
    $usuario_data=array(
        'nombre_pila'=>Input::get('nombre_pila')
        );
    // saving...
    $usuario->fill($usuario_data);
    if($usuario->save()){
        return 'success';
    }else{
        return 'fail';
    }
    return 'posted: '.$nombre_pila;
}

到目前为止,我有这段代码可以更新第一个输入 nombre_pila,重点放在焦点上。现在我还有两个输入:ap_paternoap_materno。我如何安排我的代码,以便它更新已聚焦的最新输入的信息?

编辑:

我想要的是只更新每个输入。为了实现这一点,我在每个输入中设置了标识符,这样我可以很容易地获得最近关注的输入。但首先我需要检测输入文本中的值是否已更改(在此编辑表单中,每个输入显示用户先前保存在数据库中的数据)。

因此,在 focusout 函数之前,我添加了另一个函数来检测特定输入的变化(通过其 ID 属性),如 fiddle 中所示。最后,我决定不在这里使用 focusout(),因为它很烦人,特别是如果你将鼠标放在任何输入中,post() 函数将不可避免地被调用,例如,即使我转到另一个window 或到另一个选项卡。

所以这里是 JQuery 的编辑部分,它工作正常并且只在数据库中更新相应的输入值:

//Primero detectar si hubo cambios en un input dado
                var timerid;
                $("input").on("input",function(e){
                    var currentId = $(this).attr('id');
                    //alert('Current ID value is: '+currentId);
                    var value = $(this).val();
                    //preguntar si el dato del input en donde está el cursor ha cambiado:
                    if($(this).data('lastval')!=value){
                        $(this).data('lastval',value);
                        nuevoValor=$(this).val();
                        clearTimeout(timerid);
                        timerid=setTimeout(function(){
                            //change action
                            alert('vamos a actualizar la info...Identificador: '+currentId+' Nuevo valor:'+nuevoValor);
                            //AQUÍ PONEMOS EL PROCEDIMIENTO DE ACTUALIZACIÓN DE LA INFO DEL CAMPO CORRESPONDIENTE.
                            //var currentID = $('#formedit2 input').attr('id');// http://jsfiddle.net/xstqLkz4/59/, http://www.tequilafish.com/2007/12/04/jquery-how-to-get-the-id-of-your-current-object/
                            //var newValue = $(currentId).val();
                            alert('ID es: '+currentId+' and current value is: '+nuevoValor);
                            //var editform = {identifier:currentID,value:newValue};
                            var editform = $('#formedit2').serializeArray();
                            editform.push({name:'identifier',value:currentId});//
                            //alert(editform);
                            var url = $("#formedit2").attr('action');//con esto se llama al controlador correspondiente!
                            $(this).addClass('loadinggif');
                            $.post(url, editform, function(data,status){
                                $('#formedit2 input').removeClass('loadinggif');
                                //alert(data);
                                if(data=='fail'){
                                    alert('Could not update the input field. Status:' + status);
                                    $('#formedit2 input').removeClass('loadinggif');
                                }else if(data=='success'){
                                    alert('Data updated successfully! Status: ' + status);
                                    $('#formedit2 input').removeClass('loadinggif');
                                }else if(status=='timeout'){
                                    alert('Time out. Please reload');
                                    $('#formedit2 input').removeClass('loadinggif');
                                }else if(status=='error'){
                                    alert('There has been an error. Try again later.');
                                    $('#formedit2 input').removeClass('loadinggif');
                                }else{
                                    $('#formedit2 input').removeClass('loadinggif');
                                    alert(data);
                                }
                            });//end of post() function
                            //END OF UPDATING INFO PROCESS
                        },2500);
                    };
                });//end of input part

这里是控制器,通过使用 switch 语句,控制器知道必须更新数据库中的哪个字段:

public function postEditProfile2(){
    //save data and send to form page or display a success message
    //instanciando al usuario actual:
    $id_user=Auth::user()->id;
    $usuario=User::find($id_user);
    $identifier=Input::get('identifier');
    //$nombre_pila=Input::get('nombre_pila');
    $identificando=explode('_',$identifier);
    $tabla=$identificando[0];
    $num=end($identificando);
    if($tabla=='usuario'){
        switch ($num) {
            case '01':
                $usuario_data=array('nombre_pila'=>Input::get('nombre_pila'));
                break;
            case '02':
                $usuario_data=array('ap_paterno'=>Input::get('ap_paterno'));
                break;
            case '03':
                $usuario_data=array('ap_materno'=>Input::get('ap_materno'));
                break;
            default:
                # code...
                break;
        }
        // saving...*/
        $usuario->fill($usuario_data);

        /*$usuario->fill(Input::all());*/
        if($usuario->save()){
            return 'success';
        }else{
            return 'fail';
        }
    }else{
        return 'error';
    }
 }//end of postEditProfile2() function

但现在的问题是 ajax-loader.gif,我将其添加为类的部分,$(this).addClass('loadinggif'); 不再出现。为什么?有帮助吗?

已解决: 我没有正确使用 ajax 加载程序的选择器,它是一个简单的 + 号,但没有显示,如 here 所示,所以该行是:

$('#'+currentId).addClass('loadinggif');

最后一题: 剩下的唯一问题是超时状态不会出现。例如,如果一个小时过去了而没有任何操作,我尝试修改数据但没有任何反应。没有更新。所以我必须再次刷新页面。而在Whosebug中不会出现这种情况,即使电脑已经"sleeping",我再次唤醒它,我仍然可以在不刷新页面的情况下更新信息。这怎么可能?在我的案例中,我应该怎么做才能使页面保持活动状态?

希望我没听错...

首先,使您的 jQuery 代码通用,以便它适用于每个输入。您需要做的就是更改选择器:

$('#formedit2 input[type=text]').on('focusout',function(){
    var editform = $('#formedit2').serializeArray();
    var url = $("#formedit2").attr('action');//con esto se llama al controlador correspondiente!
    $(this).addClass('loadinggif');
    $.post(url, editform, function(data,status){
        $(this).removeClass('loadinggif');
        //alert(data);
        if(data=='fail'){
            alert('No se pudo actualizar el campo. Status:' + status);
        }else if(data=='success'){
            alert('Dato actualizado exitosamente! Status: ' + status);
        }else if(status=='timeout'){
            alert('El tiempo de espera se ha agotado. Recargue la página.');
        }
    });
});

如您所见,我更改了第一个选择器以匹配所有文本输入,并将引用 nombre_pila 的那些替换为 $(this)

之后,稍微更改一下控制器,使其填充传入模型的所有输入。只需确保正确设置模型中的 fillable/guarded 属性即可。

public function postEditProfile2(){    
    $id_user=Auth::user()->id;
    $usuario=User::find($id_user);
    $usuario->fill(Input::all());
    if($usuario->save()){
        return 'success';
    }else{
        return 'fail';
    }
}

(我还删除了最后一个 return 语句,因为它永远不会到达)