NOTE: There are a lot of details here, so if anyone needs a condensed version of this, I'm happy to summarize.
I am trying to run a function in my php file, that will in turn, update a template variable. As an example, here is one such function:
function get_vehicle_makes()
{
$sql = 'SELECT DISTINCT make FROM phpbb_vehicles
WHERE year = ' . $select_vehicle_year;
$result = $db->sql_query($sql);
while($row = $db->sql_fetchrow($result))
{
$template->assign_block_vars('vehicle_makes', array(
'MAKE' => $row['make'],
));
}
$db->sql_freeresult($result);
}
I know that this function works. I am trying to access this function in my Javascript with:
function updateMakes(pageLoaded) {
var yearSelect = document.getElementById("vehicle_year");
var makeSelect = document.getElementById("vehicle_make");
var modelSelect = document.getElementById("vehicle_model");
$('#vehicle_make').html('');
$.ajax({ url: '/posting.php',
data: {action: 'get_vehicle_makes'},
type: 'post',
success:function(result)//we got the response
{
alert(result);
},
error:function(exception){alert('Exception:'+exception);}
});
<!-- BEGIN vehicle_makes -->
var option = document.createElement("option");
option.text = ('{vehicle_makes.MAKE}');
makeSelect.add(option);
<!-- END vehicle_makes -->
if(pageLoaded){
makeSelect.value='{VEHICLE_MAKE}{DRAFT_VEHICLE_MAKE}';
updateModels(true);
}else{
makeSelect.selectedIndex = -1;
updateModels(false);
}
}
The section in my javascript...
<!-- BEGIN vehicle_makes -->
var option = document.createElement("option");
option.text = ('{vehicle_makes.MAKE}');
makeSelect.add(option);
<!-- END vehicle_makes -->
... is a block loop and will loop through the block variable, vehicle_makes, set in the PHP function. This works upon loading the page because the page that loads, is the new.php that I'm trying to do an Ajax call to, and all of the PHP runs in that file upon loading. However, I need the function to run again, to update that block variable, since it will change based on a selection change in the HTML. I don't know if this type of block loop is common. I'm learning about them since they are used with a forum I've installed on my site, phpBB. (I've looked in their support forums for help on this.). I think another possible solution would be to return an array, but I would like to stick to the block variable if possible for the sake of consistency.
This is the bit of code in the php that reads the $_POST, and call the php function:
if(isset($_POST['action']) && !empty($_POST['action'])) {
$action = $_POST['action'];
//Get vehicle vars - $select_vehicle_model is used right now, but what the heck.
$select_vehicle_year = utf8_normalize_nfc(request_var('vehicle_year', '', true));
$select_vehicle_make = utf8_normalize_nfc(request_var('vehicle_make', '', true));
$select_vehicle_model = utf8_normalize_nfc(request_var('vehicle_model', '', true));
switch($action) {
case 'get_vehicle_makes' :
get_vehicle_makes();
break;
case 'get_vehicle_models' :
get_vehicle_models();
break;
// ...etc...
}
}
And this is the javascript to run the Ajax:
function updateMakes(pageLoaded) {
var yearSelect = document.getElementById("vehicle_year");
var makeSelect = document.getElementById("vehicle_make");
var modelSelect = document.getElementById("vehicle_model");
$('#vehicle_make').html('');
$.ajax({ url: '/posting.php',
data: {action: 'get_vehicle_makes'},
type: 'post',
success:function(result)//we got the response
{
alert(result);
},
error:function(exception){alert('Exception:'+exception);}
});
<!-- BEGIN vehicle_makes -->
var option = document.createElement("option");
option.text = ('{vehicle_makes.MAKE}');
makeSelect.add(option);
<!-- END vehicle_makes -->
if(pageLoaded){
makeSelect.value='{VEHICLE_MAKE}{DRAFT_VEHICLE_MAKE}';
updateModels(true);
}else{
makeSelect.selectedIndex = -1;
updateModels(false);
}
}
The javascript will run, and the ajax will be successful. I've checked the network tab and console tab, and have done multiple tests to confirm that. It appears that the block variable is not being set. Is what I'm trying to do even possible? I have a feeling that to get this answer, we'll need to know more about phpBB's template engine, and how it works with these template variable. Also, just to clarify, I think the term 'template variable' is specific to phpBB. It's the term they use for variables set in PHP, to be accessed by the HTML, and javascript files. This works through a phpBB class called 'template', and a function called 'assign_block_vars'. I don't know exactly how that work.
If anyone has done this for phpBB, or has any ideas, I would appreciate it.
Think I found the problem. At the beginning of my PHP, I have an include statement to include the PHP file containing the class for connecting to the database. In the statement $result = $db->sql_query($sql);, $db is set in this other PHP file. I don't entirely understand, but because of that, $db was outside of the scope of my function get_vehicle_makes(). I had to create a class inside my PHP file, and pass $db as a parameter to the function using:
class vehicle {
public function __construct($db)
{
$this->db = $db;
}
function get_vehicle_makes()
{
$sql = 'SELECT make FROM phpbb_vehicles
WHERE year = ' . $select_vehicle_year;
$result = $this->db->sql_query($sql);
Hope this helps.
Related
I'm currently developing a web application and I am using PHP 8.0.3.
For some reason, the Ajax request is not capable of getting the updated value of the SESSION variable unless I forcefully refresh the page. I am calling the ajax function first when the page finishes loading, and then every minute.
I am using AJAX to update the values on a CanvasJS graph.
Can someone help me identify what am I doing wrong?
First, I start the session on a global file that I require on the scripts.
session_name("mfm");
session_start();
Snippet of my current ajax request on index.php page:
$.ajax({
method: "POST",
url: "php_func/somefile.php",
success: function(data){
console.log(data);
var dbdata = JSON.parse(data);
var qtyNuts = [];
var time = [];
dbdata = dbdata.reverse();
for (i = 0; i < dbdata.length; i++) {
time[i] = dbdata[i][1];
qtyNuts[i] = dbdata[i][0];
}
...
And this is part of the php_func/some_file.php:
if(isset($_SESSION['bar']))
{
$processed = $_SESSION['bar'];
$max = count($processed);
if($max > 5)
{
$max = 5;
}
$recent_data = array_slice($processed, -$max);
foreach($recent_data as $data)
{
$kgs = $data[0] / 120.0;
array_push($kgdata, array($kgs, $data[1]));
}
echo json_encode(array_reverse($kgdata));
}
I typed /php_func/some_file.php on my localhost URL and it works, kgdata array is getting updated as the SESSION variable updates.
And this is a snipped of where the session variable is created (this script runs as soon as the page is loaded and then every minute). Update.php:
$bar = array()
if(isset($_SESSION['bar'])
{
$bar = $_SESSION['bar'];
}
$b = array(count($buffer), date("H:i:s"));
array_push($bar, $b);
$_SESSION['bar'] = $bar;
For some reason, the ajax request does not update the values in the index.php graph, unless I forcefully refresh the page. What am I doing wrong?
I tried
Checking session id. They are the same in all files.
Use $.post instead. I have the same issue.
Change the setInterval for the ajax function to be more than a minute in case there is clashing between update.php and somefile.php
I am building a Wordpress site, and using AJAX to load in subsequent pages when the user navigates, so that page transitions are nicely animated.
By default, if you load and inject a page with an embedded Ninja Form, the form simply does not display. There is very little information out there on how to achieve this. I hoped there would be an official out of the box way to get this working, but there doesn't appear to be.
What steps need to be taken in order to get the form to display on the page, when the form has been dynamically loaded with AJAX?
I have experimented with some completely undocumented code samples, and managed to figure it out, along with a few necessary tweaks and additions. I thought I'd share here in case anyone else has difficulty with this.
Step 1. Enqueue necessary JS and CSS
Add the following to your functions.php, because Ninja Forms relies on backbone js, and needs css, which won't be loaded if your initial landing page does not already have a form on it.
add_action('wp_enqueue_scripts', function () {
// enqueue ninja forms css, including for any ninja forms addons
wp_enqueue_style('nf-display', content_url('/plugins/ninja-forms/assets/css/display-structure.css'), ['dashicons'], core_dev_version(''));
wp_enqueue_style('nf-layout-front-end', content_url('/plugins/ninja-forms-style/layouts/assets/css/display-structure.css'), ['nf-display'], core_dev_version(''));
// make sure that backbone is enqueued on the page, as ninja forms relies on this
wp_enqueue_script('backbone');
}, 100);
.
Step 2. Add an AJAX function that returns the form data
You shouldn't need to edit this, just add it to your functions.php. The javascript we use in step 3 will make its own AJAX call to request some form data in a very specific format.
add_action('init', function () {
// if this is not an AJAX form request, return
if (! isset($_REQUEST[ 'async_form' ])) {
return;
}
// clear default loaded scripts.
global $wp_scripts;
unset($wp_scripts->registered);
// get the requested form id
$form_id = absint($_REQUEST['async_form']);
// retrieve the requested form
ob_start();
$form = do_shortcode("[ninja_forms id='{$form_id}']");
ob_get_clean();
// output the requested form on the page
ob_start();
NF_Display_Render::output_templates();
$templates = ob_get_clean();
$response = [
'form' => $form,
'scripts' => $wp_scripts->registered,
'templates' => $templates
];
echo json_encode($response);
// die, because we don't want anything else to be returned
die();
});
.
Step 3. Add JS helper functions to your landing page
This simply adds some helpful JS code into your site.
You can add this to functions.php as is, or include it in a separate JS file.
This is what we will use to load and initialise the form we want.
add_action('wp_footer', function () {
// adds a script to the footer
?>
<script type="text/javascript">
var NinjaFormsAsyncForm = function(formID, targetContainer) {
this.formID = formID;
this.targetContainer = targetContainer;
this.formHTML;
this.formTemplates;
this.formScripts;
this.fetch = function(callback) {
jQuery.post('/', { async_form: this.formID }, this.fetchHandler.bind(this))
.then(callback);
}
this.fetchHandler = function(response) {
response = JSON.parse( response );
window.nfFrontEnd = window.nfFrontEnd || response.nfFrontEnd;
window.nfi18n = window.nfi18n || response.nfi18n || {};
this.formHTML = response.form;
this.formTemplates = response.templates;
this.formScripts = response.scripts;
}
this.load = function() {
this.loadFormHTML(this.formHTML, this.targetContainer);
this.loadTemplates(this.formTemplates);
this.loadScripts(this.formScripts);
}
this.loadFormHTML = function(form, targetContainer) {
jQuery(targetContainer).append( form );
}
this.loadTemplates = function(templates) {
document.body.innerHTML += templates;
}
this.loadScripts = function(scripts) {
jQuery.each( scripts, function( nfScript ){
var script = document.createElement('script');
// note that eval() can be dangerous to use - do your research
eval( scripts[nfScript].extra.data );
window.nfFrontEnd = window.nfFrontEnd || nfFrontEnd;
script.setAttribute('src',scripts[nfScript].src);
var appendChild = document.head.appendChild(script);
});
}
this.remove = function() {
jQuery(this.targetContainer).empty();
}
}
</script>
<?php
}, 100);
.
Step 4. Initialise the form after you AJAX in your page
I can't tell you how to AJAX in your pages - that's a whole other topic for you to figure out.
But, once you have loaded your page content with included Ninja Form, and once that has successfully been on the page, now you need to initialise the form.
This uses the javascript helper (step 3), which in turn calls the php helper (step 2), and finally displays the form on your page!
You'll need to know the ID of the form that's been injected. My tactic was to include this as a data-attribute in my page markup.
var form_id = 1;
var asyncForm = new NinjaFormsAsyncForm(form_id, '.ninja-forms-dynamic');
asyncForm.fetch(function () {
asyncForm.load();
});
And that's about all there is to it!
Hopefully this may save others the time and effort of figuring all of this out.
For my own reasons I am using JS in a seperate script, linked into my PHP file to perform several of nearly the same function (only the images change in each function) like this:
function Clicky1(element) {
var XTag= element.parentElement.previousElementSibling.firstChild;
if (element.src == "../image1.jpg")
{
element.src = "../image2.jpg";
XTag.innerHTML = XText;
localStorage.setItem(XTag.id, XText);
}
else
{
element.src = "../image1.jpg";
XTag.innerHTML = " ";
localStorage.removeItem(XTag.id);
}
}
function Clicky2(element) {
var VTag= element.parentElement.previousElementSibling.firstChild;
if (element.src == "../image3.jpg")
{
element.src = "../image4.jpg";
VTag.innerHTML = VText;
localStorage.setItem(VTag.id, VText);
}
else
{
element.src = "../image3.jpg";
VTag.innerHTML = " ";
localStorage.removeItem(VTag.id);
}
} //this repeats 3 more times
But what I want is to just use something like "{$myDB['images']}" as all the images that I am manually inserting links to within each function are already stored in my database. - How do I go about doing this in the simplest way?
You can't just inject PHP code into your Javascript like that. If the Javascript is in a block within a .php file then you can inject the result of running some PHP code as hard-coded values into your script, but not if it's in a separate .js file, because it doesn't pass through the PHP script engine before being sent to the browser.
But this code is overly repetitive anyway - why not have the image paths as parameters to the function? Then you could only have one single re-usable function. Apart from those names, the code is identical in its functionality. And also if these functions are called from JavaScript within a .php file, then you could inject the image paths into it using PHP at that point.
You'd change the function to more like this:
function Clicky(element, img1, img2) {
var XTag= element.parentElement.previousElementSibling.firstChild;
if (element.src == img1) {
element.src = img2; XTag.innerHTML = XText;
localStorage.setItem(XTag.id, XText);
}
else {
element.src = img1;
XTag.innerHTML = " ";
localStorage.removeItem(XTag.id);
}
}
And then you could call it from a <script block embedded in a PHP file, something like this:
Clicky(someElement, "<?php echo $myDB['images']; ?>", "<?php echo $myDB['images1']; ?>");
(or whatever PHP you have to use to get to each separate image string). Then you can use the values from your PHP easily, and you also wouldn't need Clicky1, Clicky2, Clicky3 etc etc all with virtually-identical code in them.
Is it possible to return javascript function via Ajax from php? Normally I would just return a value then decide what to do with it in plain javascript, but now because I am handling Apache Cordova mobile app I want to do things differently.
account = localStorage.getItem("account");
account = JSON.parse(account);
$.ajax({
type: "POST",
url: example.php,
data: { account = account.rule }
});
.php
$isAdmin = $conn->prepare("SELECT role FROM users WHERE username = :username");
$isAdmin->bindParam(":username", $username);
$isAdmin->execute();
$result = $isAdmin->fetch(PDO::FETCH_ASSOC);
if($result){
$result = "<script>
$("header nav").append(
$("<a />").attr("href", "admin.html").text("Admin panel")
)
</script>";
}
return $result;
And then run it. Ill do another check when user redirects to the site.
Instead, consider a structured response
While what you are asking to do is possible, there are much better ways to handle this. Consider instead returning an array containing the data needed to build the links with client-side scripting. Build the Ajax to call add those links accordingly. You could expand this further to include more configurable objects, or building the html to be appended and returning that, rather than trying to run javascript eval.
function updateNav(links) {
links.forEach(function(link){
$li = $('<li></li>');
$a = $('<a></a>');
$a.prop('href',link['uri']);
$a.html(link['text']);
$li.append($a);
$('#nav').append($li);
});
}
var dummyData = {
navLinks: [
{
uri: 'http://stackoverflow.com',
text: 'StackOverflow'
},
{
uri: 'http://google.com',
text: 'Google'
}
]
};
var dummyHtml = {
navHtml: '<ol><li>Meta StackOverflow</li></ol>'
};
function ajaxSimData() {
var someAjaxObject = {};
someAjaxObject.success = function(data) {
updateNav(data['navLinks']);
};
someAjaxObject.success(dummyData);
}
function ajaxSimHtml() {
var someAjaxObject = {};
someAjaxObject.success = function(data) {
$('#nav').after(data['navHtml']);
};
someAjaxObject.success(dummyHtml);
}
$('.ajaxTriggerData').click(ajaxSimData);
$('.ajaxTriggerHtml').click(ajaxSimHtml);
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
<div id="message">
Simple Examples:<br>
<button class="ajaxTriggerData">Populate Nav from Data</button><br>
<button class="ajaxTriggerHtml">Load HTML string after Nav</button><br>
</div>
<div id="body">
<h3>Some navigation elements: </h3>
<ul id="nav">
<li>Nav1</li>
<li>Nav2</li>
<li>Nav3</li>
</ul>
</div>
PHP side to generate the response
$isAdmin = $conn->prepare("SELECT role FROM users WHERE username = :username");
$isAdmin->bindParam(":username", $username);
$isAdmin->execute();
$navLinks = [];
if($isAdmin->fetch(PDO::FETCH_ASSOC)) {
$navLinks = [
['uri' => 'admin.html', 'text' => 'Admin panel'],
];
}
return json_encode([
'navLinks' => $navLinks
]);
Yes you can - response texts are just strings - but it might not be considered a good practice, especially if you make a pattern of it. Looking at your code, it looks like what you want to do is append a link to the nav that goes to the Admin panel of your app if the user is an admin. It might be better to take the following code client-side and wrap it in a client-side function:
function appendAdminLink() {
$("header nav").append(
$("<a />").attr("href", "admin.html").text("Admin panel")
)
}
...and instead of returning that function, in PHP just return something like:
{ isAdmin: true }
Then client-side you can validate if the user is an admin, and if they are you can call appendAdminLink.
My current code is:
Play.save = function() {
//Hide the buttons
this.printButton.visible = false;
this.saveButton.visible = false;
this.backButton.visible = false;
//Force the game to re-render.
this.game.cameras.render(); //generally not recommended if you can help it
//Get the canvas information
var img = this.game.stage.canvas.toDataURL("image/octet-stream");
this.saveajax(img);
//Show UI again.
this.printButton.visible = false;
this.saveButton.visible = true;
this.backButton.visible = true;
}
Play.saveajax = function(img){
$.ajax
({
url: "http://localhost/ourthing/character/save.php",
type: "POST",
cache: false,
data: {
img: img
}
});
}
The file 'save.php' works (when i simply open the file). It will execute a query which it has to do. Problem here is: with this script i want to update a user with the given post data (img). But it doesnt execute on this request.
(i create data for var img and send this data to the saveajax function, which will open save.php to execute the query).
Im very new to JS/ajax. Does anyone can help me?
Best regards
apparently I cant comment, so my question is what are you getting on save.php
with command like
error_log(print_r($_REQUEST,true));
I suspect JSON issue here. can we see save.php?
Ok didn't see your previous comment, scrap that - your Jquery is not included.
Answer:
I had to include jQuery:
<script src="assets/js/jquery.js" ></script >
Thanks #Don'tVoteMeDown and #Lixus
Save.php file:
$db = framework::getDBO();
$data = array(
'canvas_character' => $_POST['img'],
);
$db->where('id', 1);
$db->update('ot_users', $data);
(i use my own framework)