Using jQuery to call an endpoint and populate the data on the frontend is a common task. After searching and using multiple solutions the below is my current blueprint for any ajax calls.
How can I improve the following to be faster and more efficient? I realize doing it in pure javascript will be faster but at this point I assume jQuery will be present.
Frontend - Javascript:
$(document).ready(function()
{
function callEndpoint( call_url, payload ){
return $.ajax({
url: call_url,
type: 'GET',
data: payload
});
}
$( '.get-endpoint' ).click( function() {
sSelected = $( this ).text();
console.log( sSelected );
oRequest = callEndpoint( '/play/endpoint2.php', { 'type': sSelected } );
oRequest.done(function( sJson ) {
aData = JSON.parse( sJson );
$( '.from-endpoint' ).text( aData.text );
});
});
});
Frontend - Html:
<body>
<button class="get-endpoint">Games</button>
<button class="get-endpoint">Books</button>
<button class="get-endpoint">Comics</button>
<div class="from-endpoint">Coming soon...</div>
</body>
Backend - PHP:
$aReturn[ 'text' ] = '';
if( !empty( $_GET ) )
{
if( $_GET[ 'type' ] == 'Games' )
{
$aReturn[ 'text' ] = 'Text for games';
}
else if( $_GET[ 'type' ] == 'Books' )
{
$aReturn[ 'text' ] = 'Text for books';
}
else if( $_GET[ 'type' ] == 'Comics' )
{
$aReturn[ 'text' ] = 'Text for comics';
}
}
$sJson = json_encode( $aReturn, 1 );
header( 'Content-Type: application/json' );
echo $sJson;
I don't think that this code can be more efficient in jQuery.
But you have some options left to give a more efficient feeling :
You can use pagination to get a portion of your data each time. The
less data to load, the quicker it get. And your application will be
more responsive to the user's actions. This solution is a trick for
the user, because it will take in reality more time than before to load all the data.
You can keep previous loaded data so when you click back on a button,
it won't load again the data. But, this can only be used if the data
won't change much between each click. The first time you will click
on a button, it will take the same time as before, but the next time,
it will be immediat.
Be aware that the more HTML code you load, the more it will take time to initiate JavaScript behavior on it.
Looks like your categories won't change often. You can save some bandwidth by using JavaScript localstorage or cookies to cache data. If you plan on connecting to a mysql database at somepoint you can use StoredProcedures which are variablized precompiled statements.
Since you are anyways going to use JSON and jQuery, I would suggest that you should check out the getJSON method of jQuery. I feel that it would reduce some lines of code, though I am not sure if it would help it become more efficient.
Anyways getJSON is just a shorthand of AJAX and I thought I should suggest this.
This could be a good approach for AJAX data transport browser->server->browser. Hope it suites your needs.
jQuery
$( function () {
function fetch( data ) {
var encoding = data.encoding,
url = data.url,
params = data.params,
type = ( data.type ) ? : 'GET',
cache = ( data.cache ) ? : 'false',
async = ( data.async ) ? : 'true';
return $.ajax({
url: url,
async: async,
cache: cache,
data: params,
dataType: encoding,
type: type
});
}
var options = {
url: 'controller.php',
params: {
param_one: value_one,
param_two: value_two,
param_n: value_n
},
encoding: 'json'
};
// Get the JSON feed from the server
$.when( fetch( options ) ).then( function ( response ) {
// Is there anything in the pool?
if ( response ) {
// Store the response and use it in your code
var data = response.data;
console.log( data.responseOne );
console.log( data.responseTwo );
}
});
});
PHP Controller
// Set header to application/json
header( 'Content-type: application/json' );
// Create the DB connection object
$dbc = new mysqli( DB_HOST, DB_USER, DB_PASS, DB_NAME );
// Initialize parameters array
$params = array();
// Store the query variables in an array
$query_type = ( $_GET ) ? : $_POST;
// Run foreach and store the values in an array
foreach ( $query_type as $key => $value ) {
$params[ $key ] = mysqli_real_escape_string( $dbc, $value );
}
// Now you can access passed parameters like $params['param_name']
// This would be the data obtained from DB or some server array processing, whatever
$response = array(
'data' => array(
'response_one' => 'some_value',
'response_two' => 'another_value'
)
);
// Encode the result
echo json_encode( $response );
If you don't want use pure javascript, you can improve your jQuery code with better selectors
For example, you can add an id in <div class="from-endpoint">
You can add tag in selector like this:
$('button.get-endpoint')
You can drop your getEndpoint method and just use the $.get method.
$(document).ready(function()
{
$( '.get-endpoint' ).click( function() {
sSelected = $( this ).text();
console.log( sSelected );
oRequest = $.get('/play/endpoint2.php', { 'type': sSelected });
oRequest.done(function( sJson ) {
aData = JSON.parse( sJson );
$( '.from-endpoint' ).text( aData.text );
});
});
});
You can make your code lint compliant.
$(document).ready(function()
{
$( '.get-endpoint' ).click( function() {
var sSelected = $( this ).text();
console.log( sSelected );
oRequest = $.get('/play/endpoint2.php', { type: sSelected });
oRequest.done(function( sJson ) {
var aData = JSON.parse( sJson );
$( '.from-endpoint' ).text( aData.text );
});
});
});
Use success instead of done & move the callback to it's own function
$(document).ready(function()
{
$( '.get-endpoint' ).click( function() {
var sSelected = $( this ).text();
console.log( sSelected );
$.get(
'/play/endpoint2.php',
{ type: sSelected },
insertData
);
});
});
function insertData( sJson ) {
var aData = JSON.parse( sJson );
$( '.from-endpoint' ).text( aData.text );
}
Use $.getJSON instead of $.get or $.ajax
$(document).ready(function()
{
$( '.get-endpoint' ).click( function() {
var sSelected = $( this ).text();
console.log( sSelected );
$.getJSON(
'/play/endpoint2.php',
{ type: sSelected },
insertData
);
});
});
function insertData( data ) {
$( '.from-endpoint' ).text( data.text );
}
Related
I have a couple of jQuery functions that pass PHP data to the JS function using the wordpress wp_localize_scripts function:
function mb_scripts_settings() {
// blanks
$mb_ajax_form_type = $mb_get_page_slug = $mb_redirect = $mb_redirect_time = $mb_form_disable = $mb_array = '';
// get the form type
$mb_ajax_form_type = ( is_front_page() ? 'change' : 'submit' );
// get the page slug from ID
$mb_get_page_slug = get_post_field( 'post_name', get_the_ID() );
// if the page is admin or password
if( is_page( array('admin', 'pw') ) ) {
$mb_redirect = true;
$mb_redirect_time = 3000;
$mb_form_disable = true;
if( is_page('admin') ) {
// generate the url for redirection
$mb_form_area = ( ( is_page('admin') && isset($_GET['mbtab']) ) ? $_GET['mbtab'] : null );
$mb_form_area_url = ( empty($mb_form_area) ? '/' : '/admin/?mbtab=' . $mb_form_area . '&mbform=1' );
$mb_form_area_url = get_home_url( $mb_form_area_url );
}
}
// if the page is front
if( is_front_page() ) {
$mb_redirect = false;
$mb_redirect_time = 0;
$mb_form_disable = false;
$mb_get_page_slug = 'front_page';
$mb_form_area = $mb_form_area_url = null;
}
// build the array
$mb_array = array(
$mb_ajax_form_type,
$mb_get_page_slug,
$mb_redirect,
$mb_redirect_time,
$mb_form_disable
);
return $mb_array;
}
Which would output an array with all the needed data for the JS function:
// create the script
$(function() {
// var
var mb_form_type = mb_mbtheme_js[0],
mb_form_type = '.' + mb_form_type,
mb_get_page_slug = mb_mbtheme_js[1],
mb_redirect = mb_mbtheme_js[2],
mb_redirect_time = mb_mbtheme_js[3],
mb_form_disable = mb_mbtheme_js[4];
// trigger the ajax on form type
// $("#mb_ajax_form") + mb_form_type + ( function( mb_ajax_form ) {
$("#mb_ajax_form").change( function( mb_ajax_form ) {
// stop the default function of buttons
mb_ajax_form.preventDefault();
// do the ajax
mb_ajax_form_js();
});
});
// accept the form ID
function mb_ajax_form_js() {
// get the vriables
var mb_ajax_form_data = new FormData( $("#mb_ajax_form")[0] ),
mb_ajax_form_time = 60,
mb_ajax_form_links = "#mb_ajax_form input, #mb_ajax_form submit, #mb_ajax_form button";
// do the ajax
$.ajax({
method: "POST",
data: mb_ajax_form_data,
contentType: false,
processData: false,
// the before send function
beforeSend: function( before ) {
// lock the form input and select
$( mb_ajax_form_links ).prop( "disabled", true );
},
// the success function
success: function( success ) {
// show the response
$( "#response" ).show().html( success );
// scroll to the top of the container - response divHeight
$( "section.mbcontainer" ).animate({
scrollTop: $( "#response" ).offset().top
}, "slow" );
// re-enable the submit button
// $( mb_ajax_form_links ).prop( "disabled", false );
},
// the complete function
complete: function( complete ) {
// if we are seeing the success message
if( $( "#response div" ).hasClass( "mbsuccessmessage" ) ) {
// the admin or password page conditions
if( mb_get_page_slug == 'admin' || mb_get_page_slug == 'pw' ) {
// set the redirection
setTimeout( function() { window.location.replace( mb_redirect ); }, mb_redirect_time );
// what to do with the form
$( mb_ajax_form_links ).prop( "disabled", mb_form_disable );
}
// the front page conditions
if( mb_get_page_slug == 'front_page' ) {
// set the redirection
setTimeout( function() { $(".mbsuccessmessage").slideUp(); }, mb_redirect_time );
}
}
},
// the error function
error: function( error ) {
// log the error
console.error( error );
}
});
}
However, it doesn't seem to be working as I thought it would when it wasn't being passed via the array and was all hard coded in. Things like the mb_form_type weren't working until I created a new variable with the '.' + mb_form_type.
Now it is spitting an error on the complete: function but I have also tried setting the if statement to compare as String() == String(mb_get_page_slug) == String('admin') but that didn't work either.
Is there something I am missing in the comparisons?
Your issue is one of scope. $(function() {}); creates a closure and you define your vars in that closure. Code outside the closure cant see those variables. To fix this, you have several options, here are 2 that would work:
1) move the variables to outside the closure like this:
// var
var mb_form_type = mb_mbtheme_js[0],
mb_form_type = '.' + mb_form_type,
mb_get_page_slug = mb_mbtheme_js[1],
mb_redirect = mb_mbtheme_js[2],
mb_redirect_time = mb_mbtheme_js[3],
mb_form_disable = mb_mbtheme_js[4];
// create the script
$(function() {
// trigger the ajax on form type
// $("#mb_ajax_form") + mb_form_type + ( function( mb_ajax_form ) {
$("#mb_ajax_form").change( function( mb_ajax_form ) {
// stop the default function of buttons
mb_ajax_form.preventDefault();
// do the ajax
mb_ajax_form_js();
});
});
// accept the form ID
function mb_ajax_form_js() {
// your code here...omitted for brevity
}
2) move your function inside the closure like this (note, anything calling mb_ajax_form_js will also need to be inside the closure):
// create the script
$(function() {
// var
var mb_form_type = mb_mbtheme_js[0],
mb_form_type = '.' + mb_form_type,
mb_get_page_slug = mb_mbtheme_js[1],
mb_redirect = mb_mbtheme_js[2],
mb_redirect_time = mb_mbtheme_js[3],
mb_form_disable = mb_mbtheme_js[4];
// trigger the ajax on form type
// $("#mb_ajax_form") + mb_form_type + ( function( mb_ajax_form ) {
$("#mb_ajax_form").change( function( mb_ajax_form ) {
// stop the default function of buttons
mb_ajax_form.preventDefault();
// do the ajax
mb_ajax_form_js();
});
// accept the form ID
function mb_ajax_form_js() {
// your code here...omitted for brevity
}
});
Update:
For accessing the submit and change functions using a string variable (mb_form_type), you'll need to use the "array access syntax" rather than the dot notation you have tried.
As a simple example, this would work (note that mb_form_type doesnt contain the .):
var mb_form_type = 'change';
$("#mb_ajax_form")[mb_form_type]( function( mb_ajax_form ) {
alert('This will work using array access syntax');
});
here's a working example
I've created some sample code below. You can delete items simply by clicking the text you want to delete (or the li element).
When you look at the network tab when you delete, you get back both a 204 and 200 response. Why are there two? I'm only making 1 call.
Where the heck is the request method "OPTIONS" coming from?
//Cache DOM
var $content = $( 'ul' );
var $name = $( '#name' );
var $bike = $( '#bike' );
var $addButton = $( '#add-item' );
var $liElems = $( 'li' );
//Functions
$( function () {
function addItem( data ) {
$content.append( '<li id="' + data.id + '">' + data.name + ' likes ' + data.bike + '</li>' );
}
$.ajax( {
type: 'GET',
url: 'http://rest.learncode.academy/api/sjm/bikes',
success: function( response ) {
$.each( response, function( index, bikes ) {
addItem( bikes );
});
},
error: function( ) {
console.log ( 'error loading orders' );
}
});
$addButton.on( 'click', function(){
var data = {
name: $name.val(),
bike: $bike.val()
};
$.ajax( {
type: 'POST',
url: 'http://rest.learncode.academy/api/sjm/bikes',
data: data,
success: function( response ) {
addItem( response );
},
error: function( ) {
console.log( 'error while saving' );
}
});
});
$content.delegate( 'li', 'click', function ( ) {
var id = $( this ).attr( 'id' );
var $this = $( this );
console.log ( 'delete ' + id);
$.ajax({
type: 'DELETE',
url: 'http://rest.learncode.academy/api/sjm/bikes/' + id,
success: function( response ){
$this.fadeOut( 300, function ( ) {
remove( );
});
},
error: function( ){
console.log( 'error deleting data' );
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="content">
<section>
name <input type="text" id="name">
bike <input type="text" id="bike">
<button id="add-item">add data</button>
</section>
<ul></ul>
</div>
When you try to send a XMLHttpRequest to a different domain than the page is hosted, you are violating the same-origin policy. However, this situation became somewhat common, many technics are introduced.
CORS is one of them.
In short, server that you are sending the DELETE request allows cross domain requests. In the process, there should be a preflight call and that is the HTTP OPTION call.
So, you are having two responses for the OPTION and DELETE call.
see MDN page for CORS.
Hi i'm new with prestashop 1.6 and i use jquery's $.ajax to call a PHP script . what i wan,t is to create new form when i click on button and this is my code :
in the catproduct.php :
public function clickme(){
$html = 'Click me
<div id="myFormm"></div>
<script type="text/javascript">
$( ".displayForm" ).click(function() {
$.ajax({
url: "'._MODULE_DIR_.$this->name.'/ajax.php",
context: document.body,
})
.done(function(data) {
$( "#myFormm" ).html( data );
alert( "Load was performed." );
});
})
</script>';
return $html;
}
public function renderForm()
{
$fields_form = array(
'form' => array(
'legend' => array(
'title' => $this->l('Add new category'),
'icon' => 'icon-cogs'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('FCI'),
'name' => 'FCI',
),
),
'submit' => array(
'title' => $this->l('Save')
)
),
);
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$lang = new Language((int)Configuration::get('PS_LANG_DEFAULT'));
$helper->default_form_language = $lang->id;
$helper->allow_employee_form_lang = Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') ? Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG') : 0;
$this->fields_form = array();
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitCatForm';
$helper->fields_value['FCI'] = 'ddddd';
$helper->currentIndex = $this->context->link->getAdminLink('AdminModules', false).'&configure='.$this->name.'&tab_module='
.$this->tab.'&module_name='.$this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
return $helper->generateForm(array($fields_form));
}
the ajax.php file (the ajax file call the renderForm() function to create new form):
require_once(dirname(__FILE__).'../../../config/config.inc.php');
require_once(dirname(__FILE__).'../../../init.php');
include_once('catproduct.php');
$module = new catproduct();
echo $module->renderForm();
the done function return nothing . please help me i spend two days searching for solution
Example of ajax call in Prestashop (front-office) :
$( document ).ready(function() {
var form = $('.MyForm');
form.submit(function(e) {
$.ajax({
type: 'POST',
url: '../modules/MyModule/controllers/front/MyFrontController.php',
data: $(this).serialize(),
dataType: 'json',
success: function(jsonData) {
console.log(jsonData);
}
});
e.preventDefault();
});
});
Console shows results. If not, there is a problem with php file.
Here is a sample of PHP file :
<?php
include(dirname(__FILE__).'/../../../../config/config.inc.php');
include(dirname(__FILE__).'/../../../../init.php');
include(dirname(__FILE__).'/../../classes/MyUsefulModuleClass.php');
if (Tools::getIsset('my_useful_id')) {
echo Tools::jsonEncode('Ajax return fine')); }?>
Check if config.inc.php and init.php are called. Always console.log() your results while working on it.
Then try to separate form creation, you can use only HTML, not sure if you can create forms using helpers, and show it using Ajax. I think that most of modules use HTML only
I'm using jquery-ajax to send data to a php. Upon success or failure the php sends back a response. so far everything works fine. Now my questions is how do I use an if statement in jquery to do some action using the response?
See example:
$.post("php/send.php",
{
email:$( '#email' ).val(),
name:$( '#name' ).val()
},
function(response) {
alert(response) // shows "Error!"
if (response != "" || response != "Error!") {
//do A...
} else {
//do B...
}
)};
My if statement does not work. Even the response from the php is "Error!" it will //do A.How do I fix this?
In your if conditional, the expression to the left of the short-circuit OR (ie. ||) returns true if response is not an empty string. When response = "Error!", ie. not empty, the first part of || becomes true, and //do A will execute. The expression to the right of ||, in this case response != "Error!", is simply ignored when the expression to the left of || is true.
The code posted should work if the only output from send.php is something like <?php echo "Error!"; ?>, and, i don't know if it is a typo, but closing brackets for the $.post function should be });
Method 1
Good practice is to use json format ( json_encode() ) for the response, for example:
php
<?php
// if there is an error fill the error data
$response['error'] = 'Error message!';
// else fill the correct data
$response['data'] = [ 'foo' => 'Some data', 'bar' => 'Some other data' ];
header( 'Content-Type: application/json' );
die( json_encode( $response ) );
?>
js
$.post( "php/send.php", { email: $( '#email' ).val(), name: $( '#name' ).val() } )
.done( function( response ) {
if ( response.error ) {
console.log( response.error );
return;
}
console.log( response.data );
});
Method 2
Alternatively, HTTP response code can be set manually ( http_response_code() ), so that the fail() method of jqXHR object is invoked, like this:
php
<?php
// if case of an error
http_response_code(400);
die( 'Error message!' );
?>
js
$.post( "php/send.php", { email: $( '#email' ).val(), name: $( '#name' ).val() } )
.done( function( response ) {
// success
})
.fail( function( jqXHR ) {
console.log( jqXHR.responseText );
});
Usually is not safe to respond with pure text from a php page, i suggest you to use json for the comunication between php and ajax, anyway, your code seems ok, try to add a trim() to the returned string in php
I'm trying to execute the remote code completion example in Jquery Mobile using the following url: http://demos.jquerymobile.com/1.4.0/listview-autocomplete-remote/
I use latest PhoneGap with jquery mobile version 1.4.3
the auto complete javascript code:
$(function() {
$( "#drink_brand_autocomplete" ).on( "filterablebeforefilter", function ( e, data ) {
var $ul = $( this ),
$input = $( data.input ),
value = $input.val(),
html = "";
$ul.html( "" );
if ( value && value.length > 2 ) {
$ul.html( "<li><div class='ui-loader'><span class='ui-icon ui-icon-loading'></span></div></li>" );
$ul.listview( "refresh" );
$.ajax({
url: "http://myalcoholist.com/drink-management/drink/drink-brand-autocomplete",
dataType: "jsonp",
crossDomain: true,
data: {
q: $input.val()
}
})
.then( function ( response ) {
console.log("response");
$.each( response, function ( i, val ) {
html += "<li>" + val + "</li>";
});
console.log(html);
$ul.html( html );
$ul.listview( "refresh" );
$ul.trigger( "updatelayout");
});
}
});
});
in chrome developer console i can see that the ajax call is being executed fine and the server returns a json array.
the .then() is not being executed, no ideas why.
i tried .done() instead but i got the same results.
i don't get any javascript errors.
any ideas?