CakePHP AJAX call - ajax

I am using CakePHP and this is my first project on this framework. I am going to send the value of an input to UsersController's check_username() action. And fill an element having id na with the string returned by check_username(). So far what I did is:
//in my form
<input type="text" name="data[User][username]" style="width: 60%" required="required" id="username" oninput="check_username(this.value)">
<label style="margin-left: 20px; color: red" id="na">Not Available!</label>
//after the form
<script type="text/javascript">
function check_username(un) {
$.ajax({
type: 'POST',
url: '/oes/users/check_username',
data: {username:un},
cache: false,
dataType: 'HTML',
beforeSend: function(){
$('#na').html('Checking...');
},
success: function (html){
$('#na').val(html);
}
});
}
</script>
//and my check_username() is
public function check_username(){
return 'Test string';
}
But this isn't working. Anybody know why or how to modify it so that it works?

It could be problem with your check_username controller action. CakePHP-way is to use JsonView class to send any data throw XHR (see http://book.cakephp.org/2.0/en/views/json-and-xml-views.html). It allows you to call any action with .json extension (ex.: /oes/users/check_username.json) and get response in serialized JSON format without manual conversion beetween array data and JSON.
This method is recommended for your needs, but not obligated, of course.
Now I think that CakePHP tries to render check_username view, but could not do this because you have not specified or created it. Try to change your action code to something like this:
public function check_username(){
$this->autoRender = false;
echo 'Test string';
}
Also, try not to use such code construction in the future.

CakePHP has a JS Helper to help write aJax functions. The only catch is to include jquery in your head our cake will throw jQuery errors.
Your Form:
<?php
echo $this->Form->create('User', array('default'=>false, 'id'=>'YourForm'));
echo $this->Form->input('username');
echo $this->Form->submit('Check Username');
echo $this->Form->end();
?>
The Ajax Function:
<?php
$data = $this->Js->get('#YourForm')->serializeForm(array('isForm' => true, 'inline' => true));
$this->Js->get('#YourForm')->event(
'submit',
$this->Js->request(
array('action' => 'checkUsername', 'controller' => 'user'),
array(
'update' => '#na',
'data' => $data,
'async' => true,
'dataExpression'=>true,
'method' => 'POST'
)
)
);
echo $this->Js->writeBuffer();
?>
The Function in User Controller
function checkUsername(){
$this->autoRender = false;
//run your query here
if ( $username == true )
echo 'Username is taken';
else
echo 'Username is not taken';
}

There are many examples through google. Here is a good one to visit.

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

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.

Codeigniter auto suggestion text box

I'm using codeigniter in my project and want to implement a text box which suggests related word s from the data base. In this one I want to get the ID of the selected vehicle. But so far I was only able to retrieve the vehicle names with out IDs.
The code so far,
Model
function searchVehicle($name){
$this->db->like('Name', $name, 'both');
return $this->db->get('vw_vehicle_search')->result();
}
Controller
public function vehicle_search(){
$this->load->model('model_vehicle');
if(isset($_GET['term'])){
$result = $this->model_vehicle->searchVehicle($_GET['term']);
if(count($result)>0){
foreach($result as $object)
$arr_result[] = $object->Name;
echo json_encode($arr_result);
}
}
}
View
<script type="text/javascript">
$(document).ready(function(){
$('#vehicle_name').autocomplete({
source: "<?php echo base_url();?>vehicle/vehicle_search/?"
});
});
</script>
<div class="col-md-4">
<?php
$input_data = array(
'name' => 'vehicle_name',
'id' => 'vehicle_name',
'class' => 'form-control'
);
echo form_input($input_data)?>
</div>
How can I pass the id of the vehicle with this one and get the id when i select a vehicle to insert to the db.
Thank you.
Try it in this way:
controller:
public function vehicle_search(){
$this->load->model('model_vehicle');
if(isset($_GET['term'])){
$result = $this->model_vehicle->searchVehicle($_GET['term']);
if(count($result)>0){
foreach($result as $object)
$arr_result[] = array( 'label' => $object->Name, 'value' => $object->id);
echo json_encode($arr_result);
}
}
}
View:
$(document).ready(function(){
$('#vehicle_name').autocomplete({
source: "<?php echo base_url();?>vehicle/vehicle_search/?",
select: function(event, ui) {
event.preventDefault();
$("#vehicle_name").val(ui.item.label);
//$("#vehicle_name-hidden").val(ui.item.value);
},
focus: function(event, ui) {
event.preventDefault();
$("#vehicle_name").val(ui.item.label);
}
});
});

how to create a plugin with ajax

Hi everyone I am trying to call a ajax function in my plugin, for this I saw this
tutorial But in my case never execute de ajax call.
First in the constructor I have this:
function __construct(){
add_action('init', array( $this, 'register_script'));
....
add_action('wp_ajax_aad_get_results', array($this, 'aad_process_ajax'));
}
function register_script(){
wp_register_script('myplugin', plugins_url('/includes/myplugin.js', __FILE__), array('jquery'));
wp_enqueue_script('myplugin');
wp_enqueue_script('add-ajax', plugin_dir_url(__FILE__).'includes/js/add-ajax.js', array('jquery'));
}
this function has to execute when I click in the buttom of this form
public function rbk_show_box( $post ) {
// get post meta values
$values = get_post_custom( $post->ID );
// echo '<input type="hidden" name="',$post->post_title.'_add_box_nonce" value="',wp_create_nonce(basename(__FILE__)),'" />';
echo '<form id="camposMeta" name="este" method="POST">';
echo'</form>';
echo '<form id="camposMeta" name="este" method="POST" >';
echo '<input type="hidden" name="',$post->post_title,'">';
echo '<fieldset id="campos1" class="clonedInput">';
echo '<label>Name</label>';
echo '<input type="text" name="name1" id="name1" />';
echo '<select name="select1" id="select1">';
echo '<option >Selecciona el tipo</option>';
echo '<option>Text</option>';
echo '<option>TextArea</option>';
echo '<option>File</option>';
echo '</select>';
echo'</fieldset>';
echo '<input type="button" id="btnAdd" value="+" />';
echo'<input type= "submit" id="btn_submit" value="Crear Meta Box">';
echo'</form>';
}
I create dynamic field in my form so now I need take all this field to create a metabook.
I know that a take my field like this:$('#camposMeta').serialize() but when I call the file createMetaBox.php to pass this params the program don't work!!
$('#btn_submit').click(function(){
alert('ready')
$.ajax({
// url: createMetaBox.php
data: {
action: 'aad_get_results',
//valores:$('#camposMeta').serialize()
},
success:function(){
}
});
});
any idea!!!
If you're using OO techniques, I suspect that your ajax hook should be like:
add_action('wp_ajax_aad_get_results', array( $this, 'aad_process_ajax' ) );
If you want the Ajax to execute for users who are not logged in(for example front end), you should also add:
add_action('wp_ajax_nopriv_aad_get_results', array( $this, 'aad_process_ajax' ) );
You have to post to the ajax url.
First localize your javascript after enqueing it, and make the ajaxurl available as a variable
wp_localize_script( 'quote_script', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
Then call your ajax with the ajax url variable
$('#btn_submit').click(function(){
$.ajax({
url: MyAjax.ajaxurl;
data: {
action: 'aad_get_results',
},
Also, if you echo from your php function, you'll need to do something with it in the ajax callback, eg
success: function(response) {
alert(response);
};

Action not running with CakePHP Js->submit()

I'm using CakePHP 1.3, and trying to make a simple message posting board with ajax. I'm trying to use the Js helper to submit a form on the index page, then refresh the message board's div to include the new message. This is all on a single page.
I have previously posted on this, but I wanted to rephrase the question and include some updates. The previous question can be seen here How to use Js->submit() in CakePHP?
When I came back to this project after a couple days, I immediately tested and the form worked (sort of). Submitting the form added a message to the database (it didn't display the message, but I haven't attacked that part yet). It worked 2 times, adding 2 messages. Then I opened the controller file and commented out some debug code, and it stopped working. It appears the action is not being called.
Here is my messages_controller.php:
<?php
class MessagesController extends AppController {
function index() {
$messages = $this->Message->find('all');
$this->set('messages',$messages);
}
function add() {
$this->autoRender = false;
$this->Session->setFlash('Add action called');
if($this->RequestHandler->isAjax()) {
$this->Session->setFlash('Ajax request made');
$this->layout = 'ajax';
if(!empty($this->data)) {
if($this->Message->save($this->data)) {
$this->Session->setFlash('Your Message has been posted');
}
}
}
}
}
?>
Here is the index.ctp for my Message class
<div id="guestbook" class="section_box">
<h3 id="toggle_guestbook"><div class="toggle_arrow"></div>Sign our Guestbook</h3>
<?php
echo $this->Form->create('Message');
echo $this->Form->input('name', array('label' => 'From:'));
echo $this->Form->input('text', array('label' => 'Message:'));
echo $this->Js->submit('Post Your Message', array(
'url' => array(
'controller' => 'messages',
'action' => 'add'
),
'update' => '#message_board'
));
echo $this->Form->end();
echo $this->Js->writeBuffer(array('inline' => 'true'));
?>
<div id="message_board">
<?php foreach($messages as $message) { ?>
<div class="message">
<p class="message_txt">
<?php echo $message['Message']['text']; ?>
</p>
<div>
<div class="message_name">
<?php echo $message['Message']['name']; ?>
</div>
<div class="message_date">
<small>
<?php echo $message['Message']['date']; ?>
</small>
</div>
</div>
</div>
<?php } ?>
</div>
</div>
When the submit button is clicked, I can see in the console that a POST is made to http://localhost/messages/add with the correct data. But there doesn't appear to be a response. The flash message "Add action called" is NOT set from the controller (or any of the flash messages, for that matter) and the contents of #message_board are emptied.
If I refresh the page at this point, the SECOND flash message appears ("Ajax request made"), and the contents of the #message_board are restored. However the new message was not saved, its the same 2 messages from before.
I'm stumped. I have a feeling maybe there are bigger issues causing my problem, but I can't see it. Any help would be appreciated.
But there doesn't appear to be a
response ... and the
contents of #message_board are
emptied.
That is because you haven't set what action/view to render. You have to do this manually since you have $this->autoRender set to false. You could use render() to do this. More info can be found at its respective cookbook page.
If you have $this->autoRender set to true, then it'll replace the contents of #message_board with the contents of add.ctp
The flash message "Add action called"
is NOT set from the controller (or any
of the flash messages, for that matter)
I think you have to refresh the page or the part which contains the $this->Session->flash() bit for flash messages to appear.
The fact that the flash message appeared when you refreshed the page means that it did call and run the action.
AFAIK, you can only put/print one message from the flash key in the Messages array. The flash key is where the flash messages are stored by default. Each call to setFlash() will overwrite the flash message set by older calls.
Since only the second flash message was displayed, we could say that it failed at passing at least one of the conditions following the second call to setFlash() in the controller. You might want to put debug($this->data) statements near the conditions related to $this->data to help yourself in debugging your problem.
You could also use debug() to know if your application went through a certain action or path since it will almost always be displayed.
So you could do the following to check if it passed this condition:
if(!empty($this->data)) {
debug('Passed!');
If 'Passed!' will be printed after submitting the form, we would know that it passed that condition.
However the new message was not saved
It might be because $data is empty or it failed at validation. If your $data is not empty, it might have failed at validation and since your form doesn't display the validation errors; you might never have noticed them. One way to know if it passed validation is to do the following:
$this->Message->set($this->data);
if ($this->Message->validates()) {
debug('it validated logic');
} else {
debug('didn't validate logic');
}
Ramon's solutions worked for me. Here's the updated code.
Controller add function
function add() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
$this->layout = 'ajax';
if(!empty($this->data)) {
if ($this->Message->validates()) {
if($this->Message->save($this->data)) {
$this->render('/elements/message_board');
} else {
debug('didn\'t validate logic');
}
}
}
}
}
Heres the add form view:
<?php
echo $this->Form->create('Message');
echo $this->Form->input('name', array('label' => 'From:'));
echo $this->Form->input('text', array('label' => 'Message:'));
echo $this->Js->submit('Post Your Message', array(
'url' => array(
'controller' => 'messages',
'action' => 'add'
),
'update' => '#message_board'
));
echo $this->Form->end();
echo $this->Js->writeBuffer(array('inline' => 'true'));
?>
<?php pr($this->validationErrors); ?>
<div id="message_board">
<?php echo $this->element('message_board'); ?>
</div>
I tried to use the same solution as you used but it's not working. Ajax is ok when I access it directly in the URL, and I have the impression that the click is doing nothing. When I use
<fieldset><legend><?php __(' Run 1');?></legend>
<div id="formUpdateID"><div id="#error-message"></div>
<?php
$orders=array_merge($emptyarray,$orders['r1']['Order']);
echo $this->Form->create('Order');
echo $this->Form->input('id', array('value'=>$orders['id'],'type' =>'hidden'));
echo $this->Form->input('race_id', array('value'=> $orders['race_id'],'type' =>'hidden'));
echo $this->Form->input('driver_id', array('value'=>$session->read('Auth.User.driver_id'),'type' =>'hidden'));
echo $this->Form->input('run', array('value'=>$run,'type' =>'hidden'));
echo $this->Form->input('pm', array('value'=>$orders['pm'],'error'=>$err[$run]));
echo $this->Form->input('pr', array('value'=>$orders['pr'],'error'=>$err[$run]));
echo $this->Form->input('fuel', array('value'=>$orders['fuel'],'error'=>$err[$run]));
echo $this->Form->input('pit', array('value'=>$orders['pit'],'label' => __('Pit on lap '),'error'=>$err[$run]));
echo $this->Form->input('tyre_type', array('value'=>$orders['tyre_type'],'error'=>$err[$run]));
echo $this->Js->submit('Modify', array(
'url' => array(
'controller' => 'orders',
'action' => 'ajax_edit'
),
'update' => '#error_message'
));
echo $this->Form->end();
?>
<?php pr($this->validationErrors); ?>
</div></fieldset>
in view and in controller "orders":
function ajax_edit($id=null){
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
die(debug('In Ajax'));
$this->layout = 'ajax';
debug('didn\'t validate logic');
}
echo 'hi';
}
None of the messages are displayed.
I have some hard coded JS/ajax before which is not targeting this code part.
I did copy ajax layout in th webroot/view folder.
I can see the AJAX code displayed in formatted source code
<div class="submit"><input id="submit-1697561504" type="submit" value="Modify" /></div> </form><script type="text/javascript">
//<![CDATA[
$(document).ready(function () {$("#submit-1697561504").bind("click", function (event) {$.ajax({data:$("#submit-1697561504").closest("form").serialize(), dataType:"html", success:function (data, textStatus) {$("#error_message").html(data);}, type:"post", url:"\/Webmastering\/form1C\/frame\/orders\/ajax_edit\/1"});
return false;});});
//]]>
</script>
BTW, I start getting bored of the lack of doc in cakephp and its non efficacity to realize task more complicated than just posting a post in a blog. So thank you for your help before I start destroying my computer ;)
I know it's an old topic, but I stumbled acros the same problem in my application, so now I think what Thrax was doing wrong, namely he didn't put echo $this->Js->writeBuffer(array('inline' => 'true')); in the view (or in the layout) file, like Logic Artist did, so the scripts for handling the submit button's click weren't generated.

Resources