Ajax with CakePHP and Javascript - javascript

i' m pretty new in using CakePHP and Javascript, i read many articles about request handling in cake, but i'm still confused, what i'm try to do is to send ajax request from my Javascript code to cakePHP and obtain some data in json format, i tried many ways to do this, but all the time I get simply html of page, instead of data i want to get, I have generated by default app controller class, as a url in Javascript request i use "http://localhost/pages/main" which is url of my view page where i have input controls, i wonder where in controller class should i put code responsible for handling request, and how to implement sending json response, thanks in advance
php code AppController class
public function beforeRender(Event $event)
{
// Note: These defaults are just to get started quickly with development
// and should not be used in production. You should instead set "_serialize"
// in each action as required.
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
if ($this->request->is('ajax')) {
$data = ['data1', 'data2'];
$this->set(compact('data'));
$this->set('_serialize', ['data']);
}
}
**javascript:**
var xhr = new XMLHttpRequest();
var url = 'localhost/pages/main.json';
var data = {
unit: 'someUnit',
name: this.name
};
xhr.onreadystatechange = function () {
if (xhr.readyState === XMLHttpRequest.DONE) {
console.log(xhr.response);
}
};
xhr.open('POST', url);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
xhr.send(data);

It is easier if you use routing extension
Router::extensions(['json']);
then in your controller you can pass the serialize data like this
$data = $this->Model->find();
$this->set(compact('data');
$this->set('_serialize', ['data']);
In your ajax request, just add .json extension to the url

You can start here: CakePHP official documentation for REST
Example:
// src/Controller/RecipesController.php
class RecipesController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
public function index()
{
$recipes = $this->Recipes->find('all');
$this->set([
'recipes' => $recipes,
'_serialize' => ['recipes']
]);
}
}

Related

Calling JavaScript function after updating table with PHP

I have a simple website that uses JavaScript to collect user input and sends data to PHP script (script is an external php file) via AJAX request. PHP script updates database with this information.
Now, i have a JS function on my website that i want to call only after PHP script is sucessfuly run and database updated. I don't need any data from database or PHP script, i only want to make sure that database is updated before calling this Javascript function.
This is what AJAX request looks like:
function ajax_post(){
if (typeof featureId !== 'undefined') {
// Create our XMLHttpRequest object
var hr = new XMLHttpRequest();
// Create some variables we need to send to our PHP file
var url = "parse_file.php";
var fn = featureId;
var vars = "featureId="+fn;
hr.open("POST", url, true);
// Set content type header information for sending url encoded variables in the request
hr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
// Access the onreadystatechange event for the XMLHttpRequest object
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var return_data = hr.responseText;
document.getElementById("status").innerHTML = return_data;
}
}
// Send the data to PHP now... and wait for response to update the status div
hr.send(vars); // Actually execute the request
document.getElementById("status").innerHTML = "processing...";
hilites.destroyFeatures();
featureId = undefined;
}
else {
window.alert("Select polygon first");
}
}
What is the best way to do this? Some examples would really help.
Looking at your code, you simply need to call the function around this part:
hr.onreadystatechange = function() {
if(hr.readyState == 4 && hr.status == 200) {
var return_data = hr.responseText;
document.getElementById("status").innerHTML = return_data;
// CALL YOUR FUNCTION HERE
}
}
The best solution is to use a Promise. However, this is not supported in IE 11, so you will need to use a polyfill on some browsers.
Here is an example using jQuery.
// This is the function you want to call after the script succeeds
function callbackSuccess() {
console.log('Done!');
}
// This is the data you want to submit to the PHP script
var myData = {
hello: "world"
};
// This is the actual AJAX request
$.post('/my-script.php', myData).done(function(){
callbackSuccess();
});
Add this to the end of your php save-function:
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array('status' => 'SUCCESS'));
Making the call:
$.getJSON('url_to_your_php_file.php', function(data) {
if (data.status == 'SUCCESS') {
console.log('Save complete');
}
else {
console.log('oops, something went wrong!!');
}
});
It's possible to return something like ERROR, this will return:
console.log('oops, something went wrong!!');
You may try the following:
In php you can use return code from sql statement
echo $sqlResult = $conn->query($sqlStatement);
On Javascript, you can try the following
$.ajax({
url: 'file.php',
type: 'POST',
data: {
data1 : data1,
data2: data2
},
success: function(data){
if(data == success_code){
alert("Success")
}
}
Hope this helps!
Completing ajax request without errors does not mean that the data is saved to DB without errors.
Even if your PHP script fails to save the data, it probably echos some error message or even empty output as regular HTTP response, and it would show as success as far as the ajax request goes.
If your intention is to make sure that the data is really saved before calling the JS function, then the PHP script should containg enough error handling.
If you write the PHP script to return response status code based on the real outcome of save operation, then you can rely on those status codes in ajax response handling (success = ok, error = not ok).
Bu what I usually do, is that instead of using HTTP status codes, I echo "OK" or something similar at the end of succesfull PHP execution (and "ERROR" if there are any errors), and then check for those strings in ajax response handler (hr.responseText in your code).
Maby you have to try this:
setTimeout(function(){
//your function here...
}, 500);

XMLHttpRequest() POST call in codeigniter 3 403 (Forbidden) due to csrf protection

I'm trying to make a ajax call using plain javascript XMLHttpRequest() to a codeigniter controller that has csrf and regeneration activated. it works only if I colect the data and token from a form , otherwise I get 403 (Forbidden).
here is the JS:
function test_ajax() {
var ajax = new XMLHttpRequest();
var data = {'csrf_test_name':csrfToken} ;
ajax.addEventListener("load", completeHandler, false);
ajax.addEventListener("error", errorHandler, false);
ajax.addEventListener("abort", abortHandler, false);
ajax.open("POST", base_url+'admin/test_ajax');
ajax.setRequestHeader('X-Requested-With', 'XMLHTTPRequest');
ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
ajax.setRequestHeader('csrf_test_name', csrfToken);
ajax.responseType = "json";
ajax.send(data);
function completeHandler() {
console.log(event.target.response);
}
function errorHandler() {
}
function abortHandler() {
}
}
and here is the controller in codeigniter:
class Admin extends CI_Controller{
public function __construct(){
parent::__construct();
$this->load->library('session');
$this->load->helper('url_helper');
$this->load->helper('security');
$this->load->helper('cookie');
}
public function test_ajax(){
$x = array('test1','test2');
echo json_encode($x);
//var_dump($x);
}
}
So I tried to add the token in the header also in the data to be sent, neither works not even from the first call. I would prefer a solution to make it work by including the token in the data and not in the header if possible (some browser have problmes with setting headers).
Please no jQuery solutions, I need this one to work using plain javascript.
Thanks in advance.
I found the solution , maybe this will help somebody, the data sent to the controller needs to be serialized in this format:
var data = "csrf_test_name="+csrfToken;

How to pass Django csrf token in AJAX (without jQuery)

Based on the w3schools ajax example I am trying to make a delete call and then remove the corresponding row from a table. There are plenty of answers here about how to do it using JQuery but I am not doing that. I found this answer which made me write my JavaScript like this:
function deleteFullLicense(rowid, objectid) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 204) {
row = document.getElementById(rowid);
row.parentNode.removeChild(row);
}
else {
window.alert("Something went wrong. The delete failed.");
}
};
xhttp.open("POST", "deleteLicense/" + objectid, true);
xhttp.send({'csrfmiddlewaretoken': '{{ csrf_token }}'});
}
But I get the Forbidden (CSRF token missing or incorrect.) message. How should I send the token?
Turns out if I called it X-CSRFToken instead it worked. Found out about it here if you want to read more.
function deleteFullLicense(rowid, objectid) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == 4 && xhttp.status == 204) {
row = document.getElementById(rowid);
row.parentNode.removeChild(row);
}
};
xhttp.open("POST", "deleteLicense/" + objectid, true);
xhttp.setRequestHeader("X-CSRFToken", '{{ csrf_token }}')
xhttp.send();
}
The header name X-CSRFToken actually comes from the parameter CSRF_HEADER_NAME in Django settings.py. When receiving frontend request (e.g. ajax call), Django internally checks header parameters and converts X-CSRFToken to HTTP_X_CSRFTOKEN which is default value of CSRF_HEADER_NAME .
The better approach would be to :
convert the value of CSRF_HEADER_NAME
render the converted value in previous step, to the HTML template
in the frontend code (e.g. the HTML template or separate js file), create a custom header with that value and the CSRF token on each ajax call for form submission.
Here's a quick example :
In settings.py
CSRF_HEADER_NAME = "HTTP_ANTI_CSRF_TOKEN"
In the view function of views.py
from django.conf import settings
from django.http.request import HttpHeaders
prefix = HttpHeaders.HTTP_PREFIX
converted = settings.CSRF_HEADER_NAME[len(prefix):]
converted = converted.replace('_','-')
# so the value HTTP_ANTI_CSRF_TOKEN is converted to ANTI-CSRF-TOKEN,
return Response(context={'custom_csrf_header_name':converted})
In your HTML template (not good practice, since this is just quick example)
<script>
// Note that the value is 'ANTI-CSRF-TOKEN'. when this header name goes to
// backend server, Django will internally convert it back to 'HTTP_ANTI_CSRF_TOKEN'
var custom_csrf_header_name = "{{ custom_csrf_header_name }}";
// the ajax part is almost the same as described in the accepted answer
...
xhttp.setRequestHeader(custom_csrf_header_name, '{{ csrf_token }}')
...
</script>

Ajax - don't get Request

I have a JavaScript function that I use to start a request. I need the GET parameter of this request, but trying to access it through PHP does not return anything. Any idea why?
I call the JS function in the same PHP file through which I try to access it (index.php)
JavaScript:
function aufloesung() {
var request = new XMLHttpRequest();
request.open("GET", "index.php?screen=1", true);
request.send();
}
PHP File:
<script> aufloesung(); </script>
...
echo $_GET["screen"]
But I don't get the parameter.
Its easy by using jQuery and slicing your index.php & ajaxphp files.
include jquery.js in your index.php:
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
aufloesung();
</script>
app.js:
function aufloesung() {
$.ajax({
type: "get",
url: "ajax.php?screen=1",
success: function( data ) {
alert( data );
}
});
}
ajax.php:
<?PHP
echo $_GET[ 'screen' ];
?>
You are making two separate HTTP requests.
The first one made by typing a URL into the address bar of the browser doesn't include the query string parameter but is rendered in the page.
The second one, made by using the XMLHttpRequest object, does include the query string parameter, but you don't do anything with the response so you can't see it.
You could, for example:
function aufloesung() {
var request = new XMLHttpRequest();
request.open("GET", "index.php?screen=1", true);
request.addEventListener("load", function (event) {
document.body.appendChild(
document.createTextNode(this.responseText)
);
});
request.send();
}

I can't send PHP variables to JavaScript

I'm trying to send parametres from a .php file to my Javascript but I can't even manage to send a String.
Javascript fragment:
var params = "action=getAlbums";
var request = new XMLHttpRequest();
request.open("POST", PHP CODE URL, true);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);
request.onreadystatechange = function() {
var phpmessage = request.responseText;
alert(phpmessage);
};
PHP fragment:
$deviceFunction = $_POST["action"];
if ($deviceFunction == "") $deviceFunction = $_GET["action"];
// Go to a function depending the action required
switch ($deviceFunction)
{
case "getAlbums":
getAlbumsFromDB();
break;
}
function getAlbumsFromDB()
{
echo "test message!";
}
The alert containing phpmessage pops up but it's empty (it actually appears twice). If I do this the alert won't even work:
request.onreadystatechange = function() {
if(request.status == 200) {
var phpmessage = request.responseText;
alert(phpmessage);
}
};
The readystatenchange event will be called each time the state changes. There are 5 states, see here: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#readyState
Rewrite your JS:
request.onreadystatechange = function () {
if (request.readyState == 4) {
console.log('AJAX finished, got ' + request.status + ' status code');
console.log('Response text is: ' + request.responseText);
}
}
In your code, you only check for the returned status code. The code above will check for the ready state and then output the status code for debbuging.
I know that this answer is more a comment than an answer to the actual question, but I felt writing an answer in order to include nicely formatted code.
I faced a similar problem working with Django. What I did:
I used a template language to generate the javascript variables I needed.
I'm not a PHP programmer but I'm going to give you the idea, let me now if works. The following isn't php code, is just for ilustrate.
<?php
<script type="text/javascript" ... >
SOME_VARIABLE = "{0}".format(php_function()) // php_function resolve the value you need
</script>
?>
The I use SOME_VARIABLE in my scripts.
Please specify your onreadystatechange event handler before calling open and send methods.
You also should make your choice between GET and POST method for your request.
If you want to popup your message only when your request object status is OK (=200) and readyState is finished whith the response ready (=4), you can write :
request.onreadystatechange = function() {
if (request.readyState==4 && request.status==200) {
var phpMessage = request.responseText;
alert(phpMessage);
}
};

Categories

Resources