I'm creating dynamic dropdown lists from values in my database. I'm querying the data, creating a php variable in this format:
$items = array(
'red'=>'apples,firetrucks,blood',
'yellow'=>'bus,pencil,duck'
);
I can then use the json_encode() function to encode.
{
"red":"apples,firetrucks,blood",
"yellow":"bus,pencil,duck",
}
I know the getJson is passed at file or a path like:
$.getJSON("jsondata/data.json", function(data) {
Can my json variable be passed to this function instead? The reason I want a variable to be passed, rather than a file is because my data can chance on a daily basis, ie:
$items = array(
'red'=>'apples,firetrucks,bricks',
'yellow'=>'bus,pencil,duck'
);
You need to create a PHP file that outputs the JSON you want;
In /foo.php:
echo json_encode(array(
"red" => "apples,firetrucks,blood",
"yellow" => "bus,pencil,duck",
));
... then your JavaScript should make an AJAX request to foo.php using getJSON;
$.getJSON("/foo.php", function (data) {
alert(data.red); // shows "apples,firetrucks,blood
alert(data.yellow); // you get the idea
});
... It was so tempting to make the values for your object arrays, but I resisted... somehow
Related
I'm a noobie of PHP and AngularJS.
I have a webpage that communicates to a web serves with PHP - AJAX. It queries a database, and echoes the result (a big table) in an html placeholder.
I want to print the content of that table in a downloadable PDF file when the user pushes a button.
I want to use PDFmake and now it works well for test purpose, but how can I pass that content of my table to AngularJS' app?
Maybe should I pass table's id to docDefinition content? In that case I don't know how to do that.
Note: Maybe my approach is uncorrent cause I have to relegate PHP to different tasks and use AngularJS to query the Database, but for now I want to mantain this approach.
Thank You
I suggest you use an angular service (as explained in the docs
)
var bigTableApp = angular.module('bigTable',[])
bigTableApp.factory('BigTableSrv', ['$resource',
function($resource) {
return $resource('URL_to_php_backend', {}, {
query: {
method: 'GET',
params: {param1: 'value 1', param2: 'value 2'},
isArray: true
}
});
}
]);
Then, you can use it in a controller to fetch data from the back-end and build a table structure in PDFmake's table format:
bigTableApp.controller('BigTableController', ['$scope', 'BigTableSrv',
function BigTableController($scope, BigTableSrv) {
$scope.bigTable = BigTableSrv.query();
$scope.pdfMakeTable = {
// array of column widths, expand as needed
widths: [10, *, 130],
body: []
};
$scope.printTable = function() {
pdfMakeTable.body = $scope.bigTable.map(el => {
// process each element of your "big table" to one line of the
// pdfMake table, size of return array must match that of the widths array
return [el.prop1, el.prop2, el.prop3]
});
// create the pdfMake document
let docDefinition = {
content: [ pdfMakeTable ]
}
// print your pdf
pdfMake.creatPdf(docDefinition).print()
}
}
]);
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
I have an app that has rows, each row contains data. The rows are created by the user (just cloning a sample row).
My ajax function looks like this.
save : function(el) {
//Renaming the properties to match the row index and organize
jQuery('#application-builder-layout .builder-row').each(function(row) {
// Iterate over the properties
jQuery(this).find('input, select, textarea').each(function() {
// Save original name attr to element's data
jQuery(this).data('name', jQuery(this).attr('name') );
// Rewrite the name attr
jQuery(this).attr('name', 'application[rows]['+row+'][elements]['+jQuery(this).attr('name')+']');
});
});
//Looping through each row and saving them seperately with new rowkey
setTimeout(function() {
// Iterate over the layers
jQuery('#application-builder-layout .row-box').each(function(row) {
// Reindex layerkey
jQuery(this).find('input[name="rowkey"]').val(row);
// Data to send
$data = jQuery('#application-builder-layout .row-box').eq(row).find('input, textarea, select');
//$data = $data.add( jQuery('#application-builder-layout') );
jQuery.ajax(jQuery('#form').attr('action'), {
type : 'POST',
data : $data.serialize(),
async : false,
success: function( response ) {
//console.log( response );
}
});
});
}, 500);
},
This is the jQuery, it's application style format so this function is inside a var and is called inside a submit function, the problem is not the ajax, looking at it in the console it saves the data fine, just like I have before.
The Problem I cant get all the data into the database (only the last ajax request) take a look below at "Form Data" it shows what my ajax data looks like and how it's inserting into the DB vs how it should insert, I am using json encode and usually this works, but recently I switched to OOP style coding in PHP so I am not sure if that changes anything?
The PHP:
class MyApp {
const Post_Type = 'page';
public function __construct() {
// register actions
add_action('init', array(&$this, 'init'));
}
public function init() {
// Initialize Post Type
add_action('save_post', array(&$this, 'save_post'));
}
//The main save method
public function save_post($post_id) {
// Empty the builder
if($_POST['rowkey'] == 0) {
$builder = array();
}
$builder['rows'][$_POST['rowkey']] = $_POST['application']['rows'][$_POST['rowkey']];
$builder = esc_sql(json_encode($builder));
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if($_POST['post_type'] == self::Post_Type && current_user_can('edit_post', $post_id)) {
// Update the post's meta field
update_post_meta($post_id, 'MY_DATABASE', $builder);
} else {
return;
}
}
}
The above works fine, except its not inserting the data as an array just inserting the last ajax post call, not each. I am sure in my save method I need to reconfig that somehow, but I am just hacking away and cant find info on the web, so I could really use some insight.
I hope I provided enough.
My code summed up: Just to be clear on whats going on here, let me you some basic HTML of my app.
//This gets cloned and the jQuery renames the rowkey to match the index.
<div class="row-box">
<input type="hidden" name="rowkey" value="0">
<div class="builder-row">
<textarea style="display: block;" name="html"></textarea>
<textarea style="display: block;" name="breakingbad"></textarea>
</div>
</div>
So summed up lets say there is 4 rows, the jQuery renames each row, then loops through each and submits an ajax call for each of them. Then the PHP handles the $_POST, in prior applications working with my custom DB I got it to work but working with wp database I am having issues, maybe I am missing something in my method?
Form Data: the ajax form data looks like this (this is the form data inside headers which can be found in the console(firbug) or network(chrome))
//First element
rowkey:0
application[rows][0][elements][html]:A
application[rows][0][elements][breakingbad]:123
Then if there is another row ajax posts again
//Second element
rowkey:1
application[rows][1][elements][html]:B
application[rows][1][elements][breakingbad]:456
So an and so forth, the database looks like this
{"rows":{"2":{"elements":{"html":"B","breakingbad":"456"}}}}
It should be more like this
{"rows":[{"elements":{"html":"A","breakingbad":"123"},{"elements":{"html":"B","breakingbad":"456"}]}
Holy Smokes Batman: I think I got it, It all resides inside how I handle the $_POST ill update soon with an answer..
The database looks good like this
{"rows":[
{"elements":{"html":"A","breakingbad":"123"}},
{"elements":{"html":"B","breakingbad":"456"}}]
}
Now I can continue to build.. whew this was a MASSIVE headache.
I am able to view and delete the data by passing ID in the URl in format of:
/apis/view/id.json
using:
public function view($id) {
$api = $this->Api->findById($id);
$this->set(array(
'api' => $api,
'_serialize' => array('api')
));
}
Similarly I want to implement add and edit, where I can pass data in Json format in the HTTP body and store/edit it in the database.
I couldn't follow the this solution:
CakePHP API PUT with JSON input
I couldn't understand how to use
$data = $this->request->input('json_decode');
to achieve it.
Add can simply be used as given in documentation by appending .json to it. The URL at which you post the data will become /apis.json. This will automatically access the add() method.
Assuming you pass json values email and password in such format: {"email":"abc#def.com","password":"123456"}
public function add(){
$data=$this->request->input('json_decode', true ); //$data stores the json
//input. Remember, if you do not add 'true', it will not store in array format.
$data = $this->Api->findByEmailAndPassword($data['email'],$data['password']);
//simple check to see if posted values match values in model "Api".
if($data) {$this->set(array(
'data' => $data,
'_serialize' => array('data')));}
else{ $this->set(array(
'data' => "sorry",
'_serialize' => array('data')));}
}// The last if else is to check if $data is true, ie. if value matches,
// it will send the input values back in JSON response. If the email pass
// is not found, it will return "Sorry" in json format only.
Hope that answers your question! Put is also very similar, except it will check if the data exists, if it doesn't it will create or else it will modify existing data. If you have any further doubts don't hesitate to ask :)
As explained in the linked documentation, CakeRequest::input() reads the raw input data, and optionally passes it through a decoding function.
So $this->request->input('json_decode') gives you the decoded JSON input, and in case it's formatting follows the Cake conventions, you can simply pass it to one of Model save methods.
Here's a very basic (untested) example:
public function add()
{
if($this->request->is('put'))
{
$data = $this->request->input('json_decode', true);
$api = $this->Api->save($data);
$validationErrors => $this->Api->validationErrors;
$this->set(array
(
'api' => $api,
'validationErrors' => $validationErrors,
'_serialize' => array('api', 'validationErrors')
));
}
}
This will try to save the data and return the save result as well as possible validation errors.
In case the formatting of the input data doesn't follow the Cake conventions, you'll have to transform it accordingly.
In my Controller I've have an array $data whose var dump is as follows:
array
'urls' =>
array
0 =>
array
'link_id' => string '1' (length=1)
'link_name' => string 'http://www.nytimes.com' (length=22)
'words' =>
array
0 =>
array
'keyword_id' => string '1' (length=1)
'keyword' => string 'republican' (length=10)
Array Structure:
$ data will have urls and words only but they can have multiple values. Both will not have the same cardinality.
Then I encode it as echo json_encode($data); in displayData and send this to ajax. displayData needs no POST data. The ajax request made in the View is as follows:
$.ajax({
url:"http://localhost/codeigniter/SiteController3/displayData",
success: function(response){
alert(response);
$("#user_data").html(response);
},
dataType:"json"
})
I want to access the response in my 'View' so that I can
perform json_decode($response, true) and get the associative array.
There is a chunk of code which renders this data in tabular format by
looping on the array. And before this code I want to get the
associative array.
I tried using $.getJSON instead of $.ajax but no solution. Also
tried $.each function, but on alert only getting undefined. Did
JSON.stringify which on alert displayed the JSON but not able to
send it to PHP code.
EDIT:
#fragmentedreality's answer
The content-type inconsistency is solved using the answer. But how can I access the response received on success of AJAX in html body of my View which has a chunk of PHP code for displaying data in tabular format ?
Solution:
Check my answer below.
Add
header('content-type: application/json');
to your controller (before the echo) to set the correct mime-type for you application's response.
Finally I dropped the JSON approach. I added the following line in displayData method of the Controller:
$this->load->view('data_processing', $data);
The data_processing.php is a new View that generates the HTML table I wanted to display. The response of this View is loaded in my original View by the following AJAX request:
$.ajax
({
url: "http://localhost/codeigniter/SiteController3/displayData",
}).done(function(data)
{
console.log(data);
$('#user_data').html(data);
}