I'm trying to return a query made in a controller to the view file so I can use that data in my form. But I am unable to successfully return the data without errors. I know the function is working because it returns the right data but has an error.
Here is my CustomersController fill function which is running the sql query.
public function fill(){
$layout = 'ajax';
$this->autoRender = false;
if ($this->request->is('post')) {
$id = $this->request->data['id'];
$query = $this->Customers->find()
->where([
'id' => $id
])->first();
echo json_encode($query);
}
}
and here is my blah.ctp which is the view file.
<?php use Cake\Routing\Router; ?>
<?= $this->Form->create(Null, ['type' => 'POST']) ?>
<?php
echo $this->Form->input('customer_id', ['options' => $customers, 'empty' => true,'id'=>'customers']);
?>
<?= $this->Form->end() ?>
<script>
document.getElementById('customers').addEventListener('change',function(){
var id = this.value;
var csrfToken = $('[name=_csrfToken]').val();
$.ajax({
type: "POST",
url: '<?php echo Router::url(array("controller" => "Customers", "action" => "fill")); ?>',
data: {'id' : id},
beforeSend: function(xhr){
xhr.setRequestHeader('X-CSRF-Token', csrfToken);
},
success: function(data){
alert(data);
}
});
});
</script>
Currently this is what happens when I select a customer in my drop down box which triggers the script in the view.
As you can see it returns the array of data I need but also has the error cannot emit headers. I have tried solving this error following other questions on stack overflow but can't solve it.
I've tried using $this->set instead of echo json_encode but it always returns nothing. I'm not sure what other way to do this.
First of all, If you're selecting a single record by a unique ID, you can call
->get($id) on the table object directly, instead of building a query chain with ->find().
CakePHP 3.x should automatically handle converting your view to JSON by using the RequestHandlerComponent. Typically, you must enable it if your scaffolding or installation didn't.
1) Enable request handler component. (If not already enabled) https://book.cakephp.org/3.0/en/controllers/components/request-handling.html
2) Remove the echo json_encode($query) line; you should not echo anything as this will break the request/response cycle. This is the cause of your error.
Instead, you should serialize your data to the view. Assuming you have the fetched data in $data: $this->set(compact('data')). Then, make sure you add $this->set('_serialize', ['data']) (again, assuming the data is stored in variable name 'data').
3) Reference this doc for information on how you can request the json. You can use a file extension (.json, .xml).
Also, make sure you add the 'Accept: application/json' header to your request.(https://book.cakephp.org/3.0/en/development/routing.html#Cake\Routing\Router::extensions).
I apologize for the fuzzy response. There are many ways to achieve this with CakePHP3. Please see this doc page for more information: https://book.cakephp.org/3.0/en/views/json-and-xml-views.html
Related
After hours of Googling, I can't seem to find an answer to this seemingly simple problem. I can't add data to a database and show that data without refreshing the page. My goal is to be able to create an object from a form to upload to a database, and then show all the items in database (without the page refreshing). I have tried to get AJAX working many times, but I can't seem to do that. The application works by adding stars to students, so basically I would want to be able to update a students star count without reloading the page. But right now I can't even console.log the submitted form data. My Controller code is like so:
public function addStar(){
$id = Input::get('id');
$user_id = Input::get('user_id');
if(Auth::user()->id == $user_id){
Student::addStar($id);
}
return Redirect::back();
}
And my form:
{{Form::open(array('action'=>'HomeController#addStar','id'=>'addStar','method'=>'post'))}}
{{ Form::hidden('id', $student->id, array('id'=>'id_value')) }}
{{ Form::hidden('user_id', $student->user_id, array('id'=>'user_id_value'))}}
{{ Form::submit('+')}}
{{ Form::close() }}
And my extremely poor attempts at AJAX:
$('#addStar').on('submit',function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
cache: false,
dataType: 'JSON',
url: '/addstar',
data: $('#addStar').serialize(),
success: function(data) {
console.log(data);
},
});
return false;
});
The code works fine if I settle for allowing page reloads, but I don't want that. So essentially, my question is, how do I add data to a database and show it without the page reloading? Thanks so much!
Your controller is doing a redirect after the logic, ajax won't be able to do anything with the response. A one take would be, after adding a start returning the new star rating.
public function addStar(){
$id = Input::get('id');
$user_id = Input::get('user_id');
if(Auth::user()->id == $user_id){
Student::addStar($id);
}
$star_count = //get new star count;
return Response::json(['star_count' => $star_count]);
}
Since controller now returns a json response, the success callback on $.ajax can grab it and do something (update the star count).
#codeforfood,
If you want to grab the response and show it immediately in the page without a reload then you may go with returning a JSON reponse and then handle that response at the client side Javascript for Success or Failure conditions.
Can try something like this if you want:
In the controller addStar() method response:
$data = ['star_count' => 'COUNT OF STARS'];
return json_encode($data);
In the View for that specific Star Div:
<script>
$('#stardiv).on('submit', function (e) {
$.ajax({
type: 'POST',
url: "{{URL::to('xxxxx')}}",
data: $(this).serialize(),
dataType: "JSON",
success: function (data) {
Handle the success condition here, you can access the response data through data['star_count']
},
error: function (data) {
Handle the error condition here, may be show an alert of failure
}
});
return false;
});
</script>
After all this is just one approach, you may try different one which ever suits your need.
i have tag in cakephp like this:
var url_save = "<?php echo $this->Html->url(array('controller' => 'users','action' => 'save_template')) ;?>";
$.ajax({
url : url_save,
type : "POST",
data : JSON.stringify(templates),
dataType : 'json'
});
how the controller can take the data value?
You can use $this->request->data on the Controller the usual way.
you can get json data using $this->data in controller, you can check if the request is ajax if you want using $this->RequestHandler->isAjax() but you must also add RequestHandler in component variable.
It's been 2 days now and still I can't get this problem to work.
So basically I am trying to call a php function through jquery ajax
but nothing is working, I am not sure what is the problem is...
here are my codes
the ajax
$(document).ready(function() {
$("#idCheck1").click(function(){
$.ajax({
url:'../../../../Controller/PostsController.php',
data: {action: 'update_checkbox'},
success:function(result){
// $("#dsa").html(result);
}
});
});
});
the view
<?php echo $this->Form->create("Posts", array("action" => "update_checkbox", "id" => "checkingBox")) ?>
<td>
<?php
echo $this->Form->input('Post.' . $i . '.id', array("type" => "hidden", "label" => false, "value" => $sum['posts']['id']))
?>
<?php
echo $this->Form->input('Post.' . $i . '.done', array("type" => "checkbox", "label" => false, "value" => "1", "id" => "idCheck1"))
?>
</td>
</tr>
<?php
$i++;
}
?>
</table>
<?php echo $this->Form->end(); ?>
the controller
public function update_checkbox() {
// debug($this->data);
$var = $this->Post->saveCheckBox($this->data);
$this->set("result", $var);
}
the model
public function saveCheckBox($checkbox) {
debug($checkbox);
$this->saveAll($checkbox['Post']);
}
The url
url:'../../../../Controller/PostsController.php'
looks wrong. Since this is an AJAX request that goes through the browser you can't use relative paths that try to go upwards in the folder hierarchy, as browsers url's don't work that way. You should be making that request so that it is passed through a web server, i.e. the url should look like one of the following:
url:'http://localhost/Controller/PostsController.php'
or
url:'/Controller/PostsController.php'
The first option is an absolute url, but this also makes the code a bit less flexible (suppose you change the domain from localhost to something else). The second option is a relative URL, but one that is relative to the domain root of your web server (i.e. in the example it would still resolve to localhost/Controller...).
In both cases based on what you've posted, your PHP file should live in a Controller/ folder in the document root of your site. The structure of your code however suggests that you are using a framework of some kind (e.g. Zend, Symfony or CodeIgniter)? If that is the case it would be helpful if you post information on what framework you're using as well as that might change the answer.
UPDATE
In the case of cakePHP, you should access the controller through the front controller, meaning the URL should look like this:
url:'/posts'
UPDATE 2
For the jquery side, a complete ajax request example could look like this:
$(".idCheck").click(
function(){
var idVal = $(this).val();
$.ajax({
url:'/posts/update_checkbox',
data: {id: idVal },
type: 'POST',
success:function(result){
$("#dsa").html(result);
}
});
});
Note that the URL already contains the update_checkbox action (i.e. the complete url to the action you want to execute), and the data object contains the value of the clicked element that you want to send to the server. If you want to send a complete form you could also use $('#myformselector').serialize() to convert all inputs in the form to a object suitable for the data property of the ajax request.
I am implementing a function populatig a select box using data from another select box.
//views/users/ajax.ctp
$.ajax({
url: url,
type: "GET",
dataType: "html",
data:"arr=" + result,
success: function(data){
document.getElementById(child).innerHTML = data;
}
});
As you can see from the code above the data passed by the call should be accessible in the getSectors() function under the data variable:
//controllers/users_controller.php
function getSectors() {
$this->set('data', $this->data);
$this->render('/users/ajax_data');
}
In the corresponding view I try to see the content of the data passed:
//views/users/ajax_data.ctp
<?php var_dump($data); ?>
The $data is null.
Debugging that in Firebug shows that the call is invoked properly (status 200 ok) and that the XMLHttpRequest contains parameters and values.
Do you have any suggestions what could be possibly wrong?
In order for Cake to populate the $this->data variable, the data being send needs to follow the format data[Model][field], or at least be part of the data[..] array. If it's plainly named arr, Cake won't put it in the $this->data variable.
I have a custom post type, lets call it products. When a user drags this product to the shopping cart (droppable jQuery UI), I want the key called "amount" in my custom post type to reduce by one.
So far I have a JSON function via jQuery $.ajax that looks like this:
$.ajax({ url: 'http://localhost:8888/MAMP/nogg/wordpress/wp-content/themes/twentyeleven/functions.php',
data: { postid: +id },
type: 'post',
success: function(output) {
alert("amount is reduced by 1.");
}
});
This send the id of the post to functions.php, then I use this to get the data in my functions.php
if(isset($_POST['postid']) && !empty($_POST['postid'])) {
$postid = $_POST['postid'];
$response = json_decode($postid);
remove_amount($response);
}
Which calls the function with the postid.
function remove_amount($postid) {
$amount = get_post_meta($postid, 'amount', true);
update_post_meta($postid, 'amount', $amount--);
}
This gives me a 500 error, I've made sure it's the correct ID that has been sent, and checked the name of the field containing the key (amount).
So what is my dumb self missing here?
You do not need to json_decode the $_POST['postid'] variable.
The $.ajax method serializes your data object and sends the data in your request header just like a regular POST. jQuery isn't sending JSON to your server. (You could change your ajax parameters to actually send JSON, but I wouldn't complicate your life over a wordpress install. The way you are using $.ajax is fine.)
Try it like this:
if(isset($_POST['postid']) && !empty($_POST['postid'])) {
// Make sure you do something in this function to prevent SQL injection.
remove_amount($_POST['postid']);
}
Also, what's with the +id in your data object? Is that intentional? Other than that you'll need to give us the PHP error that is causing the HTTP 500.
get_post_meta returns a string if you've set the $single param to true, which you have.
So, is your error related to trying to decrement a string value?
What about casting your amount val to an int before decrementing it?
function remove_amount($postid) {
(int)$amount = get_post_meta($postid, 'amount', true);
update_post_meta($postid, 'amount', $amount--);
}
Does the line of the error message you are getting (706) correspond to the line where you are handling your update meta?
Ok, I solved it. Apparently there's something in the WP functions file that doesn't approve of handling json content like that. Hence not recognizing the standard WP-functions (like get_post_meta), what I did was to create a blank page, had it use a custom template with the php code, then in the jquery code I linked to that WP-page.
$.ajax({ url: 'http://localhost:8888/MAMP/nogg/wordpress/?page_id=43',
data: {postid2: id },
type: 'post',
success: function(output) {
}
});
and page_id=43 is a page using the template below:
<?php
/**
* Template Name: ajax template
* Description: ajax *
* #package WordPress
*/
if(isset($_POST['postid']) && !empty($_POST['postid'])) {
remove_amount($_POST['postid']);
}
function remove_amount($postid) {
$amount = get_post_meta($postid, 'amount', true);
if($amount > 0):
update_post_meta($postid, 'amount', $amount-1);
echo $amount-1;
endif;
}
Now the code runs as it should, now I just need to do what Stephen said and add some sql-injection protection. Thanks for the answers! Got me in the right direction!