Pass data from server-side to YUI 3 JavaScript application - javascript

I am working on rewriting my application from YUI 2 to YUI 3.
Sometimes I need some data from database in my JavaScript environment. Firs option is to assign some global variables in JavaScript, but global vars is not good, so I did following in YUI 2:
app.js
YAHOO.namespace('MyApp');
YAHOO.MyApp = function() {
var currencyRates;
var userInfo;
/*
here a lot of code with event listeners and dom manipulations which uses currencyRates and userInfo variables
*/
return {
initCurrencyRates: function(newRates) { currencyRates = newRates; },
initUserInfo: function(newUserInfo) { userInfo = newUserInfo; },
}
}();
PHP
<?php
$currencyRates = array('EUR' : 1.3245, 'GBP': 1.4322, 'RUB': 0.02334); //actually it comes from database
print '<script>YAHOO.MyApp.initCurrencyRates(' . json_encode($currencyRates) . ')</script>';
$userInfo = array('Name' => 'Jhon', 'ID' => 10); //actually it comes from database
print '<script>YAHOO.MyApp.initUserInfo(' . json_encode($userInfo) . ')</script>';
?>
As you can see I use "public methods" YAHOO.MyApp.initUserInfo and YAHOO.MyApp.initCurrencyRates to pass data into JavaScript code.
Now I what to rewrite it using YUI 3:
app.js
YUI().use('node', 'event', function(Y) {
var currencyRates;
var userInfo;
/*
here a lot of code with event listeners and dom manipulations which uses currencyRates and userInfo variables
*/
})
PHP
<?php
$currencyRates = array('EUR' : 1.3245, 'GBP': 1.4322, 'RUB': 0.02334); //actually it comes from database
print '<script>???</script>';
?>
How do I provide "public methods" in my YUI 3 JavaScript code?
Or what is another solution to pass data inside JavaScript application code aviding global variables?

You have a few options:
1) Code inside YUI sandboxes has access to variables outside the sandbox, so just store the data somewhere and reference it inside your sandbox code. This only works with data, not calling methods.
Note, this doesn't involve notification of any sort, so it's up to the code in the YUI sandbox to know when the data is available.
// PHP
print '<script>YUI.namespace('Env.MyApp.data').currencyRates = ' . json_encode($currencyRates) . ';</script>';
// YUI (inside the YUI().use() callback)
var currencyData = YUI.Env.MyApp.data.currencyData;
Technically, with this approach, you could put the data anywhere globally accessible and it would work.
2) Use the shared global EventTarget Y.Global (aka YUI.Env.globalEvents) to broadcast a message that is received by an event subscription inside your sandbox.
This allows you to have a function response to the addition of data to the page, but doesn't work if the PHP generates the currency data while building the markup for the page because that's a failed race condition.
// PHP
print "<script>YUI.Env.globalEvents.fire('myapp:data', { currencyRates: " . json_encode($currencyRates) . " });</script>";
// YUI
Y.Global.on('myapp:data', function (e) {
// the data is in e.currencyRates
});
3) If the data is meant to be delivered statically and the PHP is adding it during page assembly before the YUI() call, just wrap it in a module and use() it.
// PHP
print "<script>YUI.add('myapp-currency-rates', function (Y) { Y.namespace('MyApp.data').currencyRates = " . json_encode($currencyRates) . "; });</script>";
// YUI
YUI().use('myapp-currency-rates', … function (Y) {
// the data is in Y.MyApp.data.currencyRates
});
And you have other options depending on the timing of the data transfer and relationship between the page and the php delivering the data. Stop by #yui on freenode during the week and there will be plenty of people to help figure out the best solution for you.

Related

In development, outputting troubleshooting code only works well for standard page loads, ajax presents issues

Summary: I have a solution I've built for monitoring variables and code processing in my environment. It works well for static pages, and the code below is a usable solution for that. However, if the page includes ajax calls which updates common variables after the page runs, this monitoring method isn't useful. To make it do so, I want to figure out a way to piggyback off an ajax call that will story information that's run in place, but I can't figure out how to work it into this code.
I have the following error checking file for php that I use in my development environment, the following using a magic function, register_tick_function, to store code as its run and show the variables for each step. Including it on a page allows the tick process to run...
<?php
register_tick_function(function(){
if (isset($GLOBALS["developer_debug"]) && $GLOBALS["developer_debug"] == 'active'){
$backtrace = debug_backtrace();
$line = $backtrace[0]['line'] - 1;
$file = $backtrace[0]['file'];
if ($file == __FILE__) return;
static $fp, $cur, $buf;
if (!isset($fp[$file])) {
$fp[$file] = fopen($file, 'r');
$cur[$file] = 0;
}
if (isset($buf[$file][$line])) {
$code = $buf[$file][$line];
} else {
do {
$code = fgets($fp[$file]);
$buf[$file][$cur[$file]] = $code;
} while (++$cur[$file] <= $line);
}
$line++;
if (defined('ERR_LOG')){ $error_log = ERR_LOG; } else {
$error_log = "../logs/error_log";
}
error_log("\n==========================================================\n", 3, $error_log);
error_log("\n $file : $line :: $code \n", 3, $error_log);
error_log("\n Variables: \n" . print_r(get_defined_vars(), true) . "\n", 3, $error_log);
$GLOBALS["_TROUBLESHOOTING"][] = "<code>\n $file : $line ::: ". htmlentities($code, ENT_QUOTES) . " \n</code>";
}
}, ["_SERVER" => $_SERVER, "_COOKIE"=>$_COOKIE, "_REQUEST"=>$_REQUEST, "_SESSION"=>$_SESSION, "_GLOBALS"=>$GLOBALS]);
// To use...
// declare(ticks=1);
// include_once('debug.php');
and in my direct page loads (such as index.php) I can include this js:
$(document).ready(function() {
var dev_top_button = document.createElement("Button");
dev_top_button.innerHTML = "Top Dev Data";
dev_top_button.style = "top:0;right:75%;position:absolute;z-index: 9999"
document.body.appendChild(dev_top_button);
var dev_bottom_button = document.createElement("Button");
dev_bottom_button.innerHTML = "Bottom Dev Data";
dev_bottom_button.style = "top:0;right:50%;position:absolute;z-index: 9999"
document.body.appendChild(dev_bottom_button);
$(dev_top_button).click(function(){
$("#debug_top").toggle();
});
$(dev_bottom_button).click(function(){
$("#debug_bottom").toggle();
});
});
and this on the page itself:
echo "<div class='debug_outer' id='debug_top'><h3>Developer Information</h3><div class='debug_inner'><pre>";
if (isset($GLOBALS['_TROUBLESHOOTING']) && is_array($GLOBALS['_TROUBLESHOOTING']) && ! empty($GLOBALS['_TROUBLESHOOTING'])) {
$troubleshooting_return_array = $GLOBALS['_TROUBLESHOOTING'];
} else {
$troubleshooting_return_array = ['Empty'];
}
echo print_r(["_COOKIE" => $_COOKIE, "_REQUEST" => $_REQUEST, "_SESSION" => $_SESSION, "_TROUBLESHOOTING" => $troubleshooting_return_array, "_SERVER" => $_SERVER, "_GLOBALS" => $GLOBALS], true);
echo '</pre></div></div>';
(And a similar output at the end of the page)
So, for most pages, this method to quickly check out page variables works great. And results in a nice javascript button to where I can quickly check what my start and end variables are on a page, along with a _TROUBLESHOOTING array I can easily dump whatever values I want to for quick looking over at page start and end.
So this system has been working pretty well for me for quite awhile now. The problem, however, comes with ajax calls. I've tried several different ways, but ajax calls generally want and expect data in a certain format. I'm -wanting- to make a third div for displaying data, along with a button for it, but I'm having a hard time figuring out how to piggyback any output data along with an ajax call, and it has to be called when the ajax is called in order to get how all the variables change and to track anything I'm troubleshooting. Sure, I can put an output to the error logs each time, but that's way slower on workflow and requires grepping through all the output since the last time the logs were cleared rather than simply seeing what my data is as I'm manipulating it.
Does anyone have a good idea to piggyback off of ajax calls to take use of these existing kinds of calls? Because messing with the returned values of the ajax calls will always result in bad data for the ajax call itself.
Solution was fairly straightforward after I thought about it for a while:
For ajax requests, send the data to a sub-array in session; a sub-array that's normally ignored by by the normal two print outs. Then, have a third button that's an ajax request that specifically fetches the value of that sub-array. The sub-array can be specifically filled with a sub-sub array for each ajax call that has been done, and then when fetched by the third button, it creates a div to share it and then empty the sub-array (otherwise it will bloat way too quickly), allow seeing all ajax calls since the last time the button was clicked (and appending them to the existing list, if still on the same page.)

How do I send a variable name and its value to the server and receive back a calculated response

I am new to wordpress and plugins but have a reasonable grip on php, javascript and html. I have created a plugin for wordpress which generates a page (form) which gathers information regarding a product specification. [It is actually a number of sequential forms, but for simplicity lets say it is one. I do not want to "submit" the form as there are many fields on each form and I do not want to "submit" until it is completed and they are ready to move to the next form].
I would like to be able to (re)calculate the product price when the user changes a parameter. To do this I would like to be able to pass the name of the changed parameter and its value back to the server (where all of the dependant data for the calculation is stored), and do the calculation and return the new price. At present I have a javascript function which is called with the pertinent data on an "onChange" and then modifies the div which represents the total price. this works if I compute the value locally, but now I am looking to complete the function by sending data to the server and receiving the calculated response e.g. :
function total_price(arg,value) {
***** send arg and value to server *****
***** receive total_price back from server *****
var total_div = document.getElementById("total_price");
total_div.innerHTML = "£"+total_price;
}
What code should I be putting in here and what should I have on the server in order to receive the data, do the calculation and send back the result?
I mostly have jQuery loaded in the front-end, so I'll post an answer using the jQuery framework. You'll most probably find a good vanilla snippet elsewhere if you're not looking to load a javascript library.
Front End
var html_price = 1; // Whatever you need here
// You'll notice that the ajaxurl variable below, is sent to the front-end in the second code snippet of this answer
$.post( ajaxurl, {
action: "get_total_price", // action is a special parameter Wordpress is listening for
price: html_price
}).done( function( price ) {
// Price back from the server you can use in the DOM
// You should probably send this using JSON, this example only uses a string
console.log( price );
});
Back End
// Here is where Wordpress is waiting for that special action parameter
// https://codex.wordpress.org/Plugin_API/Action_Reference/wp_ajax_(action)
add_action( 'wp_ajax_get_total_price', 'get_total_price' );
add_action( 'wp_ajax_nopriv_get_total_price', 'get_total_price' );
function get_total_price() {
$price = $_POST[ 'price' ];
if( $price ) {
// do with the price what you want
echo $price; // Echo instead of return
exit; // Remember to close up the server response here
} else {
echo '0'; // Unrealistic, but guarantees a response
exit;
}
}
// Send the AJAX URL to the front end. There are more elegant ways to do this, but for the purpose of this answer, this should work.
add_action( 'wp_head', 'add_ajaxurl_to_head' );
function add_ajaxurl_to_head() { ?>
<script>
ajaxurl = "<?php echo admin_url('admin-ajax.php'); ?>";
</script>
<?php }
At last I got it working (based upon your code and grasping the difference between the server and client contexts, which language to use where and what data is accessible). Thanks for your help. There must be scope for a single language for web development which is readable and context aware? HeHo, there I go wanting the world to change to suit me!!

PHP, Javascript, mysql, and selection lists

I'm working on a piece of some software that will grab information from a mysql database and throw it onto our form dynamically. I'm running into a couple problems, though. I'll give a quick rundown of some functionality.
When the form loads, we have a ton of selection lists. These are all populated through arrays with various keys/values in php. When I select an option from one list, we'll call it a "customers" list, on-click I need to check if that customer has a special flag (stored in the database), and update another selection list based on that data.
How I understand the core of my solution is I need to have a javascript trigger on-click, which I have. The function that is called references a php page that handles the database query through a class and it's function.
<script>
function setService()
{ // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.get('thePage.php?key=setService?customer='+customer);
}
</script>
This function then talks to my php. The CustomerProvider class works 100%. I have tested that thoroughly on other pages. The problem arises when I try to actually get my selection list to change.
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
if ($s != '')
{ ?> <script>var element = document.getElementById('ticket_service');
element.value = 'Contracted Hours';</script> <? }
else return;
}
?>
I'm coding in javascript literally for the first time ever and they kinda just threw me on this project. I know that my portion isn't being read as html or output as I intend. I know that every other part of the php and the first bit of javascript seems to be executing okay. Any help would be incredibly appreciated.
You seem to be on the right track but just for your own sanity here are a couple pointers. You shouldn't be returning Javascript from PHP for a situation like this. Instead you should be relying on Javascript promises to wait for a response containing just the data and continue the execution of your client code once you have your values returned. Take a look at this:
<script>
function setService() { // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.get('thePage.php?key=setService?customer=' + customer, function(data) {
console.log(data + ' was returned from your php script!');
if(data.hasContract=='1')
$('#ticket_service').val('Contracted Hours');
else
$('#ticket_service').val('No Contracted Hours');
});
}
</script>
And then your PHP script will just look like this:
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
if ($s != ''){
$hasContract = 1;
}
else
$hasContract = 0;
echo json_encode(array('hasContract' => $hasContract));
}
?>
Therefore returning only the data needed for the client app to continue... not application logic
Your code isn't doing anything with the output of the PHP script. If you want the output to be inserted somewhere in the DOM, you should use .load() rather than $.get.
$("#someelement").load('thePage.php?key=setService?customer='+customer);
This will put the output into <div id="someelement">. If the output contains <script>, the script will be executed.
If you know the result is just a script, you could use $.getScript() instead of $.get. Then the output should just be the Javascript, not enclosed in HTML tags like <script>.
The problem here is that you are not using the result from the server. Your JavaScript may indeed be correct, but the browser never sees or runs it. From the docs:
Request the test.php page, but ignore the return results.
$.get( "test.php" );
Try this code, which utilizes the $.getJSON() shortcut function. I've written two versions, which you can see commented in the code. One moves the logic for determining contract status into the JS. Either should work.
PHP
<?
if(isset($_GET['key']) && $_GET['key'] == 'setService')
{
$customer = $_GET['customer'];
$customer = intval($customer);
$s = CustomerProvider::getHasContract($customer);
// Default output
$output = array('hasContract' => false);
// Customer has contract
if ($s != '')
$output['hasContract'] = true;
echo json_encode($output)
// Alternative: PHP just returns getHasContract, JS determines action
// (this would replace $ouput, conditional, and echo)
// echo json_encode(array("hasContract" => $s));
}
?>
JavaScript
function setService()
{ // The customer's "id" grabbed from the aforementioned customer selection list
customer = $('#customer').val();
$.getJSON('thePage.php?key=setService?customer='+customer, function(result) {
// Alternative
// if (result.hasContract != "")
if (result.hasContract)
{
var element = document.getElementById('ticket_service');
element.value = 'Contracted Hours';
}
});
}
As others wrote, your code doesn't do a thing with the GET variables.
the element "ticket_service" doesn't exists on page and even if it was, the code has no impact on the page that sent the request, you should print/echo the result you want to display/return and then manipulate it with JS/Jquery.
since I'm against GET and pro POST which is safer method, here's an example with POST:
JS:
function postSomthing(customerID){
$.post(
'thePage.php',
{key:'setService',customer:customerID},
function(data){
if(data!='x'){
$('#ticket_service').val(data)
}
else{alert('no ticket');/*whatever you want to do*/}
});
}
PHP(thePage.php) :
if(isset($_POST['key']) && $_POST['key'] == 'setService'){
$customer = intval($_POST['customer']);
$s = CustomerProvider::getHasContract($customer);
if ($s != ''){echo 'x';/* false, or whatever you want*/}
else{echo 'Contracted Hours';}
}
notes:
you should create an element with the id "ticket_service" in the viewed page and not in the backstage one.

POST Slim Route not working

I'm using Slim for development. All my GET routes are working just fine, but whenever I use POST, I get "unexpected result". Please have a look at how I've implemented slim and that "unexpected error".
index-routes.php (index root file)
<?php
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim(array(
'debug' => true
));
require_once 'site-index.php';
require_once 'routes/default-routes.php';
$app->contentType('application/json');
$app->run();
?>
routes/default-routes.php
<?php
$app->post('/login',function(){
echo 'AllHailSuccess!';
})
?>
origin of POST request called via AJAX
function try1()
{
var value1 = "afsfesa";
API.call('/login','text','POST',function(data){console.log(data)},{var1:value1});
}
AJAX Call API
var API = {
call:function(url,returnType,reqType,callback,data){
var data = (!!data) ? data : {};
var callback = (!!callback) ? callback : function(){};
$.ajax({
dataType: returnType,
type:reqType,
crossDomain: true,
xhrFields: { withCredentials: true },
url: url,
data:data,
success:callback,
error:function(data){
console.log("Error!");
console.log(data);
}
});
}
}
"Unexpected error": When I execute try1(), THE POST ROUTE DOES GETS EXECUTED SUCCESSFULLY but the contents (The entire code in plain-text) of site-index.php (Which I called in root index-routes.php file) also gets logged along with it. The reason why I imported site-index.php in the first place, is because it acts like a "main stage" for my site. It's the only page I want to load and user navigates within it.
I want to know:
Why I'm getting this type of output?
Is my approach alright? I think importing my main-stage file from index- routes is causing this. Is there any other way of doing this?
Any help is appreciated. Thank you.
Your Slim calls are going to return anything that is displayed on the page.
There are a few ways to work around this:
Nest all of your page renders inside the route and don't render full pages for AJAX routes.
Modify your AJAX calls to search the returned DOM to find the relevant information.
In your example shown, AllHailSuccess! will be displayed after all of the content in site-index.php
Many people use templating software to render their pages and then use a service to render their page via the template. For more basic sites, I would recommend you create a simple service to display content.
Here's a simple example of a Viewer class I use in my project(s)
class Viewer {
/**
* Display the specified filename using the main template
* #param string $filepath The full path of the file to display
*/
public function display($filepath) {
//set a default value for $body so the template doesn't get angry when $body is not assigned.
$body = "";
if (file_exists($filepath)) {
$body = get_include_contents($filepath);
} else {
//You want to also return a HTTP Status Code 404 here.
$body = get_include_contents('404.html');
}
//render the page in the layout
include('layout.php');
}
}
/**
* Gets the contents of a file and 'pre-renders' it.
* Basically, this is an include() that saves the output to variable instead of displaying it.
*/
function get_include_contents($filepath, $params = array()) {
if (is_file($filepath)) {
ob_start();
include $filepath;
$ret = ob_get_contents();
ob_end_clean();
return $ret;
}
return false;
}
Your routes that you want to display the page layout to the user should look something like this now:
$app->get('/', function() {
(new Viewer())->display('home.html');
});
This is by no means a comprehensive solution because it does not address proper HTTP status codes and files are referenced directly in your code which can get messy, but it's a good starting point and its quick to mock something like this up.
If you want to continue in this direction, I would recommend you take a look at the Slim v2 Response Documentation and create a class that constructs and returns Response objects. This would give you much more flexibility and power to set HTTP status codes and HTTP Return headers.
I highly recommend checking out Slim v3 Responses as well because Slim 3 uses PSR-7 Response objects which are standard across multiple frameworks.

Howto: PHP/Javascript communication

As I'm developing my WebIDE, I keep coming up with questions that I cannot answer myself. This is because the project is supposed to help others create what they would "normally" create, but faster (i.e. as automated as possible). In this light, my question is how to you implement a PHP backend?
Here is what I do. I like to create "functions" that the client JavaScript can call. Usually, I send (via POST and JSON) a variable called "action" which holds the name of the "function" I am calling (as well as any arguments I wish to send it). The PHP code, then, looks something like this:
if(issset($_POST['action'])) {
//function foo(arg1,arg2)
if($_POST['action'] == 'foo') {
$arg1 = $_POST['arg1'];
$arg2 = $_POST['arg2'];
//do stuff
}
}
I can still reference other real functions I create in PHP, but I find that this is a nice way to organize everything and easy to implement in both JavaScript and PHP.
What do you do?
Edit 1: Ok, based on the first two answers to this question, I do not think I am explaining myself well.
I am asking how do you create a PHP back end. The idea is that you have your AJAX client written in JavaScript (or maybe something else, it doesn't matter), and then it will call your backend PHP with POST or GET data. Based on this data, your backend will do what it needs to do (maybe it will simply update the database, and maybe even return information, again: it doesn't matter).
The question now is: how do you tell it what to do? What do you send via POST/GET and how do you interpret it in your backend?
I send all data to the backend in a big GET array.
actionpage.php?action=post&parameters[parameter1]=value1&parameters[parameter2]=value2
If you print_r($_GET), on the PHP side you'll see:
array(
"action" => "create",
"parameters" => array("parameter1"=>"value1","parameter2"=>"value2")
)
What this does is allow you to loop through your parameters. You can say in the pap
if($_GET['action'] == 'create'){
foreach($_GET['parameters'] as $key=>$value){ //something
The question now is: how do you tell
it what to do? What do you send via
POST/GET and how do you interpret it
in your backend?
Choose your own conventions. For example use an "action" value in your JSON data that tells the action, then add more parameters. You can spy on various websites's Ajax messages with Firebug extension in Firefox if you want to see what other websites do.
For example the Json POST data could be:
{
action: "create",
fields: {
firstname: "John",
lastname: "Doe",
age: 32
}
}
To which you could reply with the ID of the newly created record.
To delete the record:
{
action: "delete",
keys: {
id: 4654564
}
}
etc.
In the php ajax handler you could have something as simple as a switch:
$jsonData = Services_Json::decode($_POST['json']);
switch ($jsonData->action)
{
case "save":
if (validate_json_data($jsonData->fields))
{
UsersPeer::create($jsonData->fields);
}
break;
case "delete":
/* etc */
}
// return a json reply with
$jsonReply = new stdClass;
$jsonReply->status = "ok";
$jsonReply->statusMessage = "Record succesfully created";
echo Services_Json::encode($jsonReply);
exit;
Javascript, say prototype Ajax.Request responder function will output the error message in a specially created DIV if "status" is not "ok", etc...
I use a front page controller which handles my routing. If you set up mod-rewrite you can have very clean endpoints where the first segment of your url refers to the controller (class) and then the subsequent segments would refer to the methods inside followed by the parameters being passed to the method.
http://domain.com/class/method/param1/param2
this website will answer all your ajax questions. I found it really helpful.
http://ajaxpatterns.org/XMLHttpRequest_Call
You need to organize functions? It's called 'class'.
/// todo: add error processing
$name=$_GET['action'];
$args=json_decode($_GET['args']); /// or just subarray, doesn't matter
/// 'Action' is constant here but in reality you will need more then one class for this
/// because you will want modules in your framework
if(method_exists('Action',$name))
call_user_func_array(array('Action',$name),$args);
else { /* incorrect parameters processing */ }
/// Ajax-available functions are here
class Action
{
public static function action1()
{
echo 'action1';
}
public static function action2()
{
echo 'action2';
}
}
I do something very similar. What you need is a JSON object to pass back to the javascript. When you are done with your PHP, you can call json_encode to pass an object back to the front end. From there you can do more with it in Javascript or format it however you want.
There is more information on a similar question here:
Best way to transfer an array between PHP and Javascript
Edit: After reading your edit, I think what you are doing is fine. When you send the AJAX request from Javascript include a variable like "action", or whatever youd like. From there you can check what the action is via a case and switch statement.
I usually write the php functions as normal functions.
fn1(arg1, arg2){
//do stuff here
}
fn2(arg3){
//do stuff here
}
I pass the name of the function in a variable called action. Then do this:
foreach($_POST as $key => $value)
$$key = $value;
To assign create variables of the same name as the arguments.
Then use a switch-case to call the appropriate function like so:
switch($action){
case 'fn1':fn1(arg1,arg2);
break;
case 'fn2':fn2(arg3);
break;
}
Is this what you are looking for?
Edit: You could use the PHP SOAP and XML-RPC extension to develop a webservice, where if you specify the function name in the SOAP request, that function will be automatically executed (you don't have to write the switch-case or if). I've used it in Java, but am not sure how exactly it works in PHP.

Categories

Resources