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: https://stackoverflow.com/questions/26960929/laravel-4-when-i-retrieve-info-from-database-into-input-text-1-extra-space-is-a/26961224?noredirect=1#comment42683960_26961224-->
        </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属性),就像这个小提琴一样。最后,我决定不在这里使用 focusout(),因为它很烦人,特别是如果你将鼠标放在任何输入中,post() 函数将不可避免地被调用,例如,即使我转到另一个窗口或另一个选项卡。

所以这里是 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');//https://stackoverflow.com/a/23266812/1883256, 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});//https://stackoverflow.com/a/13362942/1883256
                            //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 加载器正确使用选择器,这是一个缺少的简单 + 符号,如下所示,因此该行是:

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

最后一个问题:剩下的唯一问题是不会显示超时状态。例如,如果一个小时过去了,没有任何操作,我尝试修改数据,但没有任何反应。没有更新任何内容。所以我必须再次刷新页面。这在 Stackoverflow 中不会发生,即使计算机一直处于"睡眠状态"并且我再次唤醒它,我仍然可以在不刷新页面的情况下更新信息。这怎么可能?在我的情况下,我应该怎么做才能使页面保持活动状态?

我希望我理解正确...

首先,使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';
    }
}

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