I have a form where a user can update his details. This update is done by using the jQuery focusout function and Ajax to update the database.
In this example, i have three text inputs. I have tested the first input where it is updated when the user goes to the next input. A loader icon appears while that input is being updated.
For that first input i have created a controller and its corresponding JQuery code.
However, if i had a form of 10 inputs, i would have to do this 10 times. My question is: how do i simplify this? so i just have to code it once.
Here is the form:
<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>
And below the form, i have this JQuery code:
<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>
And the controller is:
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;
}
So far i have this code to update the first input, nombre_pila, on focus out. Now i have two inputs more left: ap_paterno and ap_materno. How can i arrange my code so that it updates the information of the most recent input that has been focused out?
EDIT:
What I want is to update only each input. To achieve this, i have set up identifiers in each input in such a way i can get easily which input has been recently focused out. But first i need to detect if the value in input text has been changed (in this edit form, each input displays the data saved in the database previously from the user).
So, before the focusout function, i have added another function to detect changes of a specific input (through its ID attribute) like in this fiddle . Finally, i decided not to use the focusout() here, since it turned out to be annoying, especially if you put the mouse in any input, the post() function will be unavoidably called, for example, even if i go to another window or to another tab.
So here is the edit part of the JQuery, which is working fine and it is updating in the database only the corresponding input value:
//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
And here is the controller where by using the switch statement, the controller knows which field must be updated in the database:
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
But now the problem is that the ajax-loader.gif, the part where i add it as a class, $(this).addClass('loadinggif');
no longer appears. Why? Any help?
SOLVED: I was not using the selector correctly for the ajax loader, it was a simple + sign that was missing, like shown here, so the line is:
$('#'+currentId).addClass('loadinggif');
Final question: The only problem left is that the timeout status won't appear. For example, if one hour passes by without any action, i try to modify the data and nothing happens. Nothing is updated. So i have to refresh the page again. And this doesn't happen in Stackoverflow, even if the computer has been "sleeping" and i wake it up again, i can still update information without refreshing the page. How is that possible? What should i do to keep alive the page in my case?