Is updating codeigniter db-session data clientside via ajax possible? - ajax

I'm using codeigniter with encrypted sessions in the database and I'm using a twitter bootstrap modal to update some user details in a form.
I use jquery validation on the form and in the submitHandler I post the data via ajax and close the modal.
submitHandler: function (form) {
document.getElementById("edit-profile-submit-button").disabled = true;
$('.modal-ajax-loader').show();
$.ajax({
type: $(form).attr('method'), // 'Post'
url: $(form).attr('action'), // 'profile/edit_basic_details'
data: $(form).serialize(),
success: function(data, status){
$(form).html(data);
$('.modal-ajax-loader').hide();
setTimeout(function() { $('#edit-profile-details').modal('hide'); }, 2000);
},
error: function(data, status) {
$(form).html(data);
}
});
return false;
}
and here is the model function called from the controller with the same name,
function edit_basic_profile() {
$screenname = $this->security->xss_clean($this->input->post('screenname'));
$firstname = $this->security->xss_clean($this->input->post('firstname'));
$lastname = $this->security->xss_clean($this->input->post('lastname'));
$email = $this->security->xss_clean($this->input->post('email'));
$bio = $this->security->xss_clean($this->input->post('bio'));
$data = array(
'screen_name' => $screenname,
'first_name' => $firstname,
'last_name' => $lastname,
'email' => $email,
'bio' => $bio,
);
try{
// Run the update query
$this->db->where('profile_id', $this->session->userdata('profile_id'));
$this->db->update('profiles', $data);
// Let's check if there are any results
if($this->db->affected_rows() == 1)
{
// Setup the session information for the user
$this->session->set_userdata($data);
return true;
}
// If the previous process did not update rows then return false.
error_log("profile_model, edit_basic_profile(): There were no affected rows");
return false;
} catch(PDOExceprion $e) {
error_log("profile_model, edit_basic_profile(): ".$e);
return false;
}
}
I can update the values that changed on the page in the submitHandler also and of course the session on the server is updated in the model.
$("#profile-screenname").html($(screenname).val());
$("#profile-bio").html($(bio).val());
The problem is when I open the modal again it grabs the user details from the session data in the browser cookie and grabs the original data unless the page has been refreshed after the first update.
(form data is loaded like this);
<input type="text" class="input-large" id="firstname" name="firstname" placeholder="First Name" value="<?php echo $this->session->userdata('first_name'); ?>">
"<?php echo $this->session->userdata('first_name'); ?>" on the second time i open the modal before any page refresh loads the old data.

Sure, you just need to call an ajax url which updates/sets new session data:
HTML+JS
---> Ajax call
----> $this->session->set_userdata('key','new-value');
----> session and db updated.
Done.
Also notice and change all these:
$screenname = $this->security->xss_clean($this->input->post('screenname'));
to this:
$screenname = $this->input->post('screenname',true);
which is exactly the same result

Related

Laravel ajax is not returning success data

I am trying to achieve a functionality, If I select a category in dropdown, then in next dropdown, subcategory of that chooces category will appear. I wrote below ajax in script tag for it.
$("#category").change(function(e){
e.preventDefault();
var category = $("#category").val();
$.ajax({
type:'POST',
url:"{{ route('ajaxRequest.post') }}",
data:{category:category},
success:function(data){
alert(data.success);
$("#subcategory").replaceWith(data.subcats);
}
});
});
Here is my route setup for the same
Route::get('add_product', [dashboardController:: class, 'addProduct']);
Route::post('add_product', [dashboardController::class, 'getSubCategories'])->name('ajaxRequest.post');
This is my controller function
function getSubCategories(Request $request){
//$input = $request->all();
$subCategoryList = DB::table('ajax_categories')->where('pid', $request->post('category'))->get();
$sub = '<option desabled selected>Choose sub category</option>';
foreach($subCategoryList as $subCategory):
$sub .= '<option value="'.$subCategory->id.'">'.$subCategory->category.'</option>';
endforeach;
return response()->json(array(
'success' => 'Success',
'subcats' => $sub
));
}
Everything seems fine, I am not getting what causing it to be fail.
Screenshot of network tab
On clicking on checkbox, I got this in reponse
You are echoing result before returning response so ajax is not able to parse json properly.And other is csrf token not passed properly.
In ajax you can pass csrf token like below
data:{_token: "{{ csrf_token() }}",category:category},
instead of appending in controller better do like this
function getSubCategories(Request $request){
$subCategoryList = DB::table('ajax_categories')->where('pid', $request->post('category'))->get();
$view=(string)view('dropdown',['subCategoryList'=>$subCategoryList])
return response()->json(array(
'success' => 'Success',
'subcats' =>$view
));
}
in your view dropdown.blade.php you can
#if(isset($subCategoryList)&&count((array)$subCategoryList))
#foreach($subCategoryList as $key=>$value)
<option value="{{$subCategory->id}}">{{$subCategory->category}}</option>
#endforeach
#endif

Laravel Ajax on Update data getting Success Message on same Page

i am trying to update data using Ajax in Laravel, my data is being updated successfully but when i click on update it's success message is showing on next page, i want it to show message and updated data on same Page without loading page.
Laravel Controller:
public function update(Request $request, $id)
{
$teacher = Teacher::find($id);
$teacher->efirst = $request->efirst;
$teacher->esecond = $request->esecond;
$teacher->save();
return response()->json([
'status' => 'success',
'msg' => 'esecond has been updated'
]);
}
AJAX function: Update.Js,
jQuery(document).ready(function($) {
$("#update-form").submit(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: "teachers/" + $('#update-id').attr("value"),
dataType: 'json',
headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') },
data : $(this).serialize(),
success: function (data) {
let teacher = Object.entries(data.teacher);
teacher.forEach(item => { $(`[name=${item[0]}]`).val('item[1]'); });
},
});
});
});
view:
it contains table to show list of teacher with edit, and form under table with update button.
My data is being updated, but i don't want page reload. maybe something to do with append?
if you want to refresh the data
you can make this
var table = $('#tableId');
table.DataTable().ajax.reload();
this command can reload the data,
also in your view,
you can make the button
type="button"
or add to the form
onsubmit="return false;"

Regenerate CRSF token codeigniter on submit Ajax

Hi I am looking for the process of regeneration of csrf token in codeigniter when ever a form is submitted using ajax. I want the token to be regenerated without page refresh. Is there any way to do that.
There are two solutions I use at different times depending on the situation.
1. Slightly messy way but recommended
Get the token name and hash value in your controller and set it somewhere on your page as a data field (wherever you choose). For instance
// get the data and pass it to your view
$token_name = $this->security->get_csrf_token_name();
$token_hash = $this->security->get_csrf_hash();
// in your view file, load it into a div for instance
<div id="my_div" data-token="<?php echo $token_name; ?>" data-hash="<?php echo $token_name; ?>"
Now in your js ajax code, you can just read the data values in "my_div" to get the right data for your ajax call.
It is made much easier if you have a genuine form on your page, in which case rather than using some div, just do not use form_open on the form, but instead create the hidden form field yourself, so you can read it easily via js.
<input type="hidden" id="my_data" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />
This is the important bit: Of course after sending post data, you need to refresh the token hash value (in your form input field or a div data, however you have chosen to do it). Write a js function called 'refresh_csrf_data' and use 'GET' to get the data and update the fields. This function can then be called whenever you have done an ajax post.
So every ajax call reads the token data, does the call, then refreshes the token data ready for the next call.
2. Easy but less secure
Alternatively, you can disable CSRF for your ajax calls by using the
$config['csrf_exclude_uris'] = array('controller/method');
in the config file for CSRF settings.
3. Even easier but also less secure and I do not use it
Finally, you could turn off regenerating CSRF hash on every submission
$config['csrf_regenerate'] = FALSE;
But, do so with caution. This can open you up to certain types of attacks.
The answer that is best for you depends entirely on the type of page, the usage, if users are logged in at the time or not, is it mission critical stuff or minor stuff, is it financial etc.
Nothing is entirely secure, so it is a compromise sometimes. Personally I would do it with CSRF on full regenerate, no exceptions in the URI's, and reload the token and hash data whenever I needed to. It seems complicated and it is to explain, but once you have done it once, it is genuinely easy to do again and again whenever you need it, and your site will be far more secure than simply avoiding the issue with the other options.
The solution that worked for me is that for subsequent ajax post when CSRF is enabled for every request is to make a GET request in AJAX Success when request fails because token has expired. Then have a hidden field that continue to be updated with latest token and if at the time of making request it has expired you make a GET REQUEST to fetch latest TOKEN and then evoke click event on function that submits form or function making POST request which means the function has to be passed "this" or ID as part of parameter.This makes the user not to realize the process of renewing token in the background
I find using the form helper function works better with Codeigniter
CSRF and stops throwing the CSRF error If you use normal html input
will keep throwing CSRF error.
http://www.codeigniter.com/user_guide/helpers/form_helper.html#form_input
http://www.codeigniter.com/user_guide/helpers/form_helper.html#form_password
Here is a example AJAX
<?php echo form_open('controller/example', array('id' => 'form-login'));?>
<?php
$username_array = array(
'name' => 'username',
'id' => 'username',
'class' => ''
);
echo form_input($username_array);
?>
<?php
$password_array = array(
'name' => 'password',
'id' => 'password',
'class' => ''
);
echo form_password($password_array);
?>
<?php
$submit_array = array(
'name' => 'submit',
'id' => 'submit',
'class' => '',
'value' => 'Submit',
'type' => 'submit'
);
echo form_input($submit_array);
?>
<?php echo form_close();?>
<script type="text/javascript">
$('#submit').click(function(e){
e.preventDefault();
var post_data = {
'username' : $('#username').val(),
'password' : $('#password').val(),
'<?php echo $token_name; ?>' : '<?php echo $token_hash; ?>'
};
$.ajax
({
type: 'post',
url: "<?php echo base_url('example/');?>",
data: post_data,
dataType: 'json',
success: function(response)
{
if (response['success'] == true) {
// Success
} else {
// Error
}
}
});
});
</script>
Example
public function index() {
$data['token_name'] = $this->security->get_csrf_token_name();
$data['token_hash'] = $this->security->get_csrf_hash();
$this->load->view('login_view', $data);
}
public function example() {
$data = array('success' => false, 'messages' => array());
$this->form_validation->set_rules('username', 'username', 'required');
$this->form_validation->set_rules('password', 'password', 'required');
if ($this->form_validation->run() == false) {
foreach ($_POST as $key => $value) {
$data['messages'][$key] = form_error($key);
}
} else {
$data['success'] = true;
}
echo json_encode($data);
}
if it's not on session then you controller will be like this
public function save_date() // or whatever function you like
{
$regen_token = $this->security->get_csrf_hash();
$data = array(
"data" => $this->input->post('datas'),
);
$insert = $this->w_m->save($data);
echo json_encode(array("regen_token" => $regen_token));
}
in your ajax will be look like this:
$.ajax({
url: "your url",
type: "POST",
data: { your data },
dataType: "JSON",
success: function(data)
{
$("name or id of your csrf").val(JSON.stringify(data.regen_token)).trigger("change"); // this will be the function that every post you'll request and it automatically change the value of your csrf without refreshing the page.
},
error: function(errorThrown)
{
console.log(errorThrown);
}
});
in the callback add an array of the csrf hash.

Yii2: ajax form validation on an ajax submitted form

I'm wondering if any Yii2 experts can help me understand how best to work with ajax forms combined with Yii ajax validation. I think I can explain the issue without taking you through all of my code.
I am working on a Promo Code entry form where the user enters their promo code into the form, the form is submit via ajax. We then perform a database lookup for the promo code details, validate the code and if the code validates, we want to display the registration form that is hidden on the page.
I have a custom validation function for the form field "code", which is the active field in a model scenario named "register".
class UserCode extends ActiveRecord
{
...
public function scenarios()
{
return [
'register' => ['code'],
];
}
public function rules()
{
return [
[['code'], 'required'],
[['code'], 'validateUserCode', 'on' => ['register']],
];
}
public function validateUserCode($attribute, $params)
{
// perform all my custom logic to determine if the code is valid
if ($code_invalid) {
$this->addError($attribute, 'Sorry, this code is invalid.');
}
}
...
}
Then in the controller, as the Yii2 Guide suggests, I trap this ajax validation with the following code:
public function actionValidate() {
$model = new UserCode(['scenario' => 'register']);
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
// no logic can be run after the above code b/c the form is submit with ajax
// and therefore always trapped in the Yii::$app->request->isAjax conditional
}
The above code all works fine and if I remove focus from the $form->field($model, 'code') field on my form, Yii's ajax validation kicks in and displays my custom error message based off of my custom validation logic.
My challenge arises when I go to submit the form. The form submission is also handled through ajax, and therefore the controller action always returns the result of the ActiveForm::validate($model); because if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) will get apply to both the ajax form validation AND on the form submit.
With the above approach, I am forced to return only the results of the ajax validation and not any json data that I may need for additional client side validation, such as displaying the registration form after a valid use code is submitted through the ajax form.
I realize that I can set 'enableAjaxValidation' => false on the ActiveForm and then return my own json data inside the if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) condition. If I do this, I am able to show the registration form because I have my own json data to work with.
Is there a way to have ajax validation on a form that is submitted with ajax? How could you trap the ajax validation separately from the ajax form submission to handle the two events in different manners?
Any suggestions or alternate approaches are GREATLY appreciated!
You should set up validationUrl with a different URL compared to the URL that you are submitting the form to. In this way you can have the validation function that would validate and return the return ActiveForm::validate($model); and the normal submit form that does something else.
You can read more about validationUrl here:
I have found solution :
Form :
<?php
$form = ActiveForm::begin(['id' => 'form-add-contact', 'enableAjaxValidation' => true, 'validationUrl' => Yii::$app->urlManager->createUrl('contacts/contacts/contact-validate')]);
?>
Submit Via Ajax :
<?php
$script = <<< JS
$(document).ready(function () {
$("#form-add-contact").on('beforeSubmit', function (event) {
event.preventDefault();
var form_data = new FormData($('#form-add-contact')[0]);
$.ajax({
url: $("#form-add-contact").attr('action'),
dataType: 'JSON',
cache: false,
contentType: false,
processData: false,
data: form_data, //$(this).serialize(),
type: 'post',
beforeSend: function() {
},
success: function(response){
toastr.success("",response.message);
},
complete: function() {
},
error: function (data) {
toastr.warning("","There may a error on uploading. Try again later");
}
});
return false;
});
});
JS;
$this->registerJs($script);
?>
Controller :
/*
* CREATE CONTACT FORM AJAX VALIDATION ACTION
*/
public function actionContactValidate() {
$model = new ContactsManagement();
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
$model->company_id = Yii::$app->user->identity->company_id;
$model->created_at = time();
\Yii::$app->response->format = Response::FORMAT_JSON;
return ActiveForm::validate($model);
}
}
/**
* Quick Add Contact Action
* #param type $id
* #return type
*/
public function actionAddContact() {
$model = new ContactsManagement();
if (Yii::$app->request->isAjax && $model->load(Yii::$app->request->post())) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($model->validate()) {
$flag = $model->save(false);
if ($flag == true) {
$transaction->commit();
return Json::encode(array( 'status' => 'success', 'type' => 'success', 'message' => 'Contact created successfully.'));
} else {
$transaction->rollBack();
}
} else {
return Json::encode(array('status' => 'warning', 'type' => 'warning', 'message' => 'Contact can not created.'));
}
} catch (Exception $ex) {
$transaction->rollBack();
}
}
return $this->renderAjax('_add_form', [
'model' => $model,
]);
}

Ajax Form submit

I am new to Ajax. i wanna submit a form through Ajax and save the data sent to the database.
Something like the Facebook Status update - where text area is disabled and then submited. once its saved in the database it comes back and updates the status message on the top. and again the text area is enabled.
this is my form
<?php echo $form->create('StatusMessage', array('type' => 'post', 'url' => '/account/updateStatus', 'id' => 'updateStatus')); ?>
<?php echo $this->Form->input('id', array('value' => $user['User']['id'],'type' => 'hidden')); ?>
<?php echo $this->Form->textarea('message', array('value' => 'What have you been eating ?')); ?>
Edited: Modified as suggested by 0 RioTera
Cakephp Action
function updateStatus() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
$this->layout = 'ajax'; //THIS LINE NEWLY ADDED
$this->data['StatusMessage']['pid'] = 0;
$this->data['StatusMessage']['commenters_item_id'] = $this->data['StatusMessage']['item_id'] = $this->User->Item->itemId('1', $this->data['StatusMessage']['id']);
unset($this->data['StatusMessage']['id']);
//debug($this->data);
if($this->User->Item->StatusMessage->save($this->data)) {
return true;
} else {
echo 'not saved';
}
} else {
echo 'no';
}
}
Javascript code
$(document).ready(function () {
var options = {
target: '#output2',
// target element(s) to be updated with server response
beforeSubmit: showRequest,
// pre-submit callback
success: showResponse, // post-submit callback
// other available options:
//url: url // override for form's 'action' attribute
//type: type // 'get' or 'post', override for form's 'method' attribute
//dataType: null // 'xml', 'script', or 'json' (expected server response type)
clearForm: true // clear all form fields after successful submit
//resetForm: true // reset the form after successful submit
// $.ajax options can be used here too, for example:
//timeout: 3000
};
$('#updateStatus').submit(function () {
// make your ajax call
$(this).ajaxSubmit(options);
return false; // prevent a new request
});
function showRequest(formData, jqForm, options) {
$('#StatusMessageMessage').attr('disabled', true);
}
function showResponse(responseText, statusText, xhr, $form) {
$('#StatusMessageMessage').attr('disabled', false);
alert('shdsd');
}
});
Using jquery and http://jquery.malsup.com/form/ plugin:
$(document).ready(function() {
var options = {
target: '#message', // target element(s) to be updated with server response
beforeSubmit: showRequest, // pre-submit callback
success: showResponse // post-submit callback
};
$('#updateStatus').ajaxForm(options);
});
function showRequest(formData, jqForm, options) {
$('#StatusMessageMessage').attr('disabled', true);
}
function showResponse(responseText, statusText, xhr, $form) {
$('#StatusMessageMessage').attr('disabled', false);
}
I didn't try it but I hope it helps you
i hope that this tutorial will help
http://mohammed-magdy.blogspot.com/2010/10/ajaxformsubmitter.html
This is a function I use to submit forms in cakephp 3.x it uses sweet alerts but that can be changed to a normal alert. It's very variable simply put an action in your controller to catch the form submission. Also the location reload will reload the data to give the user immediate feedback. That can be taken out.
$('#myForm').submit(function(e) {
// Catch form submit
e.preventDefault();
$form = $(this);
// console.log($form);
// Get form data
$form_data = $form.serialize();
$form_action = $form.attr('action') + '.json';
// Do ajax post to cake add function instead
$.ajax({
type : "PUT",
url : $form_action,
data : $form_data,
success: function(data) {
swal({
title: "Updated!",
text: "Your entity was updated successfully",
type: "success"
},
function(){
location.reload(true);
});
}
});
});
This is what a simple action would look like in the controller;
public function updateEntity($id = null){
$entity = $this->EntityName->get($id);
$entity = json_encode($this->request->data);
$this->EntityName->save($entity);
}

Resources