timing of JSON AJAX Response in Jquery - php

I think this is more down to timing than code, so really I am looking for best practice advice on how best to get a JSON response.
<script type="text/javascript">
$(window).load(function() {
$('#messages').append('<img src="images/loading.gif" alt="Currently Loading" id="loading" />');
var ideaid = <?php echo $_GET['ideaid']; ?>;
$.ajax({
url: 'sql/ajaxsql.php',
type: 'POST',
data: 'switch=commentList&ideaid=' + ideaid + '&filter=sortdate',
dataType: 'json',
success: function(result) {
var len = result.length;
var html;
console.log('length= ' + len);
$('#response').remove();
console.log(result);
for(var i = 0; i < len; i++) {
var pic = '<img src="https://graph.facebook.com/' + result[i].user_id + '/picture&type=small" align="middle" />';
var authname;
FB.api('/' + result[i].user_id + '?fields=name', function(AuthName) {
console.log(AuthName);
alert(AuthName.name);
authname = AuthName.name;
});
html = '<p>' + result[i].comment + '<br><hr>Date Added: ' + result[i].date + ' by ' + pic + ' ' + authname + '<br><hr><hr></p>';
$('#comms').append(html);
}
$('#loading').fadeOut(500, function() {
$(this).remove();
});
}
});
return false;
});
</script>
With this code, it fires off to get comments regarding a certain idea (idea_id). The comments only holds the Users ID (facebook). When all the data is back, the success then sorts the data ready to print to the screen in some order.
As part of the success, I have the date, time, FB image and name as part of the Author Info under each comment.
Date and Time, works. Image using the graph works, but the name is a bit late of the window loading, and so misses it's call, so comes back as undefined and then the Alert pops up with the name. I understand ajax is meant to do this.
Whats the best way to get round this.
Thank you in advance.
Andrew
EDIT
I have been unable to make this work, even with the suggestions below.
EDIT AGAIN Just seen bf new updated version as below. would also have worked. But I have spent a day on this one function and dare not to play.
As soon as the FB.api comes into play, I could not get the values from out side it. So I took a different approach.
Rather than ajax, I used the query from the PHP side that gets the data, including the uid and then json queried that, and bolted it onto the (mysql_fetch_array) array as follows:
$gc_result = mysql_query($gc_query);
while ($result = mysql_fetch_array($gc_result)) {
$jsonURL = "https://graph.facebook.com/" . $result['user_id'] . "/";
$json = json_decode(file_get_contents($jsonURL), true);
$result["name"] = $json['name'];
$data[] = $result;
}
echo json_encode($data);
Now I have that, I can then do the following and call it within the jQuery:
for(var i = 0; i < len; i++) {
var pic = '<img src="https://graph.facebook.com/' + result[i].user_id + '/picture?type=small" align="middle" />';
html = '<p>' + result[i].comment + '<br><hr>Date Added: ' + result[i].date + ' by ' + pic + ' ' + **result[i]['name']** + '<br><hr><hr></p>';
$('#comms').append(html);
}
This all works great, and I am a complete novice to programming jquery and using Facebook API and JSON, but even I sit back and am pretty impressed with this solution. Before I get carried away, are there any potential flaws in this, performance or security wise ???
Thanks again in Advance.
Andrew

The call to FB.api is probably asynchronous (another ajax request), so you have to move the code after it to inside the FB.api callback:
FB.api('/' + result[i].user_id + '?fields=name', function(AuthName) {
console.log(AuthName);
alert(AuthName.name);
authname = AuthName.name;
html = '<p>' + result[i].comment + '<br><hr>Date Added: ' + result[i].date + ' by ' + pic + ' ' + authname + '<br><hr><hr></p>';
$('#comms').append(html);
});
You also have a variable scope problem because of the for loop. One of the ways to fix this is to use a separate function to create the callback. Add this right after your $(window).load block, before </script>:
function createFbApiCallback(jsonResult) {
return function(AuthName) {
var authname = AuthName.name;
var pic = '<img src="https://graph.facebook.com/' + jsonResult.user_id + '/picture&type=small" align="middle" />';
var html = '<p>' + jsonResult.comment + '<br><hr>Date Added: ' + jsonResult.date + ' by ' + pic + ' ' + authname + '<br><hr><hr></p>';
$('#comms').append(html);
}
}
Then change your loop to this:
for(var i = 0; i < len; i++) {
FB.api('/' + result[i].user_id + '?fields=name', createFbApiCallback(result[i]));
}

If you have to execute code that relies on a callback function inside another callback function, execute your code inside the most inner callback function. In your case, move all that is out of the FB API callback to be inside it, so all your DOM manipulation is done only when both the AJAX response and the FB.api response has returned.

Related

AJAX call from inside a Widget in Yii2?

I would like to create a Widget for my Yii2 project that will based on a few parameters given in the View create an AJAX call that updates a portion of my View.
Basically I have a Postcode field that when updated will look up the corresponding town in a different PHP file. I created something that works, but I was wondering if this is the right (or only?) way to do what I'm looking for. I don't want to have to rewrite the AJAX call as I want to be able to reuse this functionality on several forms and thus fields in my project.
I call the Widget in my View like this:
<?= SearchWidget::Widget(['id' => 'customerform-postalcode',
'dataTarget' => 'cities',
'targetId' => 'customerform-city',
'targetType' => 'dropdown']);?>
and in the Widget I basically have only a run() function which echoes the AJAX call to the page.
public function run()
{
$jScript =
'<script>'
. '$("#' . $this->id . '").change(function(){'
.'$.ajax({'
. 'url: "../scripts/search.php",'
. 'data: {'
. 'needle: $("#' . $this->id . '").val(),'
. 'haystack: "' . $this->dataTarget . '"'
. '},'
. 'type: "POST"'
. '}).done(function(data){'
.'var targetType = "' . $this->targetType . '";'
.'if (targetType=="dropdown") {'
. '$("#' . $this->targetId . '").empty();'
. 'var obj = jQuery.parseJSON(data);'
. '$.each(obj, function(key, value) {'
. '$("#' . $this->targetId . '").append("<option>" + value + "</option>");'
. '});'
. '} else {'
. 'var obj = jQuery.parseJSON(data);'
. '$("#' . $this->targetId . '").val(obj);'
. '}'
. '});'
. '})'
.'</script>';
echo $jScript;
}
First off, I've only just started working with Yii and frameworks so I'm really unsure if this is the correct way to go about it. My first instinct says this is too messy and there should be a better way to do it. Any help is appreciated.
Personally I don't like to write JS code in my PHP files. So I would try to get the JS in a separate .js file.
I would change my SearchWidget to echo an input field with some additional attributes that will provide the JavaScript with the right variables. So my postcode input field would look something like:
<input type="text" name="postcode" id="postcode" class="search-field" data-target="cities" data-targetid="customerform-city" data-targettype="dropdown" />
Then you can rewrite your JS to something like below (untested).
$('.search-field').change(function() {
var id = $(this).attr('id');
var data_target = $(this).data('target');
var target_id = $(this).data('targetid');
var target_type = $(this).data('targettype');
$.ajax({
url: "../scripts/search.php",
data: {
needle: $("#" + id).val(),
haystack: data_target
},
type: "POST"
}).done(function(data) {
if (target_type == "dropdown") {
$("#" + target_id).empty();
var obj = $.parseJSON(data);
$.each(obj, function(key, value) {
$("#" + target_id).append("<option>" + value + "</option>");
});
} else {
var obj = $.parseJSON(data);
$("#" + target_id).val(obj);
}
});
});
Then put this JS file somewhere and register it in the init part of your widget.

Create line break in WhatsApp message

I have been working on WhatsApp sharing message using:
whatsapp-button.js
$_u.="Product Name:".$_productName."\n";
$_u.="Sku:".$_productSku."\n";
Share
How to add a line break:
I have tried \n, \r\n, PHP_EOL, and %0D%0A, but it just displays as text.
If you want to send an only text containing newline
use this %0a
link =`whatsapp://send?text=%0a‎Hello%0aWorld`;
If you want to send some url link with text containing newline
var encodedURL = encodeURIComponent(some_url);
link =`whatsapp://send?text=${encodedURL}%0a‎Hello%0aWorld`;
Now embedded this link in anchor tag
<a href=link> Click here! </a>
To create a line break in WhatsApp you can use this command. It's working fine and I am using it:
use `%0a`
For example:
smsContain = "*Greetings from " + cname + " ,%0a %0aM/s. " + txtName.Text + " %0a %0aYour Bill for Advertisement is generated ; %0a %0aBill Date :- " + DateTime.ParseExact(dateTimePicker1.Text, "dd/MM/yyyy", null).ToString("dd/MM/yyyy") + " %0a %0aBill no :- " + lblBillNo.Text + " %0a %0aBilling Amount of Rs. " + lblNet_Amt.Text + " %0a %0aAdvertisement Published in " + news + " in " + Edi + " edition,%0a %0aReleased Date : " + DateTime.ParseExact(DateTime.Parse(dt).ToShortDateString(), "dd/MM/yyyy", null).ToString("dd/MM/yyyy") + ".%0a %0aPlease find the Bill attached below, and request you to please release the payment ASAP. %0a %0a %0aAny descripancy in regards to this Bill to reported to us immediately.%0a %0a %0aAlways at your Service....* ";
smsContain = smsContain.Replace("&", "+%26+");
https://wa.me/+99123456789?text=Line%0aBreak
The %0a represents the line break
I got one working solution:
HTML:
$_u.="Product Name:".$_productName."\n";
$_u.="Sku:".$_productSku."\n";
<a data-text="<?php echo $_u; ?>" data-link="" class="whatsapp">Share</a>
JS:
var isMobile = {
Android: function() {
return navigator.userAgent.match(/Android/i);
},
BlackBerry: function() {
return navigator.userAgent.match(/BlackBerry/i);
},
iOS: function() {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
},
Opera: function() {
return navigator.userAgent.match(/Opera Mini/i);
},
Windows: function() {
return navigator.userAgent.match(/IEMobile/i);
},
any: function() {
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
}
};
$(document).on("click", '.whatsapp', function() {
if( isMobile.any() ) {
var text = $(this).attr("data-text");
var url = $(this).attr("data-link");
var message = encodeURIComponent(text) + " - " + encodeURIComponent(url);
var whatsapp_url = "whatsapp://send?text=" + message;
window.location.href = whatsapp_url;
} else {
alert("Please share this in mobile device");
}
});
There is a solution in here which basically is using:
whatsappMessage = window.encodeURIComponent(whatsappMessage)
Try to use 
. It is a special HTML code.
For example:
Hello!
How are you today?
will get a result like this:
Hello!
How are you today?

POST to php via AJAX with json data

Trying to post textbox values to database via json .getJSON - at this point I'm just trying to see if the json post to the page, I have the UPDATE query working fine...
following is not posting as desired:
CODE:
$(document).on("click", ".submit", function(event){
alert($(this).text());
var form_data = {
FDID: $('.fdid-1').val(),
CHOICE1: $('.choice-1').val(),
CHOICE2: $(".choice-2").val()
};
$.getJSON("modify.php",form_data,function(data){
switch(data.retval){
case 0: $("#status").html("Update successful!");
break;
case 1: $("#status").html("Unable to update!");
break;
default: $("#description").html("Database error, please try again.");
break;
}
});
});
modify.php:
<?php
header('content-type: application/json; charset=utf-8');
header("access-control-allow-origin: *");
$fdid = json_decode($_POST['FDID']);
$choice1 = json_decode($_POST['CHOICE1']);
var_dump($choice1);
// This is in the PHP file and sends a Javascript alert to the client
$message = $fdid;
echo "<script type='text/javascript'>alert('$message');</script>";
?>
MORE of CODE:
$.each( data, function ( i, val ) {
($('<div>')
.attr({
'data-role': 'collapsible',
'data-content-theme': 'c',
'data-collapsed': 'true',
'id': 'cResults'
})
.html('<h4>' + this.LastName + ', ' + this.FirstName + '</h4>'
+ '<ul data-role="listview" data-filter="true" data-filter-placeholder="Search Choices..." data-inset="true" class="makecollapsibleul">'
+ '<li><form id="productForm" action="modify.php" method="post">'
+ '<label for="fdid-1">FDID:</label>'
+ '<input type="text" name="fdid-1" class="fdid-1" value=' + this.FDID + '>'
+ '</li><li>'
+ '<label for="text-1">Choice 1:</label>'
+ '<input type="text" name="choice-1" class="choice-1" value=' + this.C1 + '>'
+ '</li><li>'
+ '<label for="text-2">Choice 2:</label>'
+ '<input type="text" name="choice-2" class="choice-2" value=' + this.C2 + '>'
+ '</li><li>'
+ 'IP: ' + this.IPADDRESS + '</li><input type="submit" class="submit" value="UPDATE" /></form><li>'
+ 'Pick Date: ' + this.PICKDATE + '</li>'
+ '</ul>'))
.appendTo('#primary');
//$(".title").append('<li>'+orderNum+' -- '+itemNum+'</li>');
$('#makecollapsible').collapsibleset().trigger('create');
$.mobile.hidePageLoadingMsg();
You should not be calling json_encode() to get the parameters. They're sent using www-form-urlencoded format, and PHP takes care of decoding them.
You need to call json_encode to encode the result you want to send back.
<?php
header('content-type: application/json; charset=utf-8');
header("access-control-allow-origin: *");
$fdid = $_POST['FDID'];
$choice1 = $_POST['CHOICE1'];
//var_dump($choice1);
// This is in the PHP file and sends a Javascript alert to the client
$message = $fdid;
$result = array('retval' => 0,
'code' => "<script type='text/javascript'>alert('$message');</script>");
echo json_encode($result);
?>
You know that $.getJson() does, according to the documentation,
Load JSON-encoded data from the server using a GET HTTP request.
So you won't find any values in $_POST. Use $_GET or $_REQUEST to get your data.
Just noticed that you don't have an element with id="save" but one with class="save". As submit events are only fired by <form> elements, try to attach a click callback to your button like this:
$(".save").click(function(e) {
e.preventDefault();
// your code
});

Jquery/Ajax and PHP rendering TR

I am scraping sites, and I am doing this one at a time, and then trying to get the results to display AS I get them. I am trying to render one TR at a time, but instead, it does every single one, and then renders ALL the TRs.
Here is the call to javascript:
<body onload="getOffers(companies , {$scraped}, {$isbn13});">
Here is the JS/Jquery function:
function getOffers($company_ids, $scraped, $isbn)
{
if($scraped)
{
$.ajaxSetup({cache: false});
for(var $id in $company_ids)
{
$.ajax({
url: "../get_offer.php",
data: "id=" + $company_ids[$id] + "&isbn=" + $isbn + "&code=" + $id,
dataType: "html",
success: function(data) {
$("#results tbody:last").append(data);
}
});
}
}
else
{
return true;
}
}
And here is the PHP page:
<?php
require_once 'scrape.php';
require_once 'include.php';
$id = requestValue('id');
$isbn = requestValue('isbn');
$code = requestValue('code');
$page = curlMultiRequest(isbn10($isbn), $id);
$offer = getOffer($code, $page[$code], isbn10($isbn));
print "<tr><td>". $offer['company']."</td><td>". $offer['offer_new'] . "</td><td>" . $offer['offer_used']."</td></tr>";
?>
I tried returning the sting I am printing, but that didn't even work. How can I make it print each table row to the screen as the data is retrieved?
EDIT: so I tried adding this:
print "<tr><td>". $offer['company']."</td><td>". $offer['offer_new'] . "</td><td>" . $offer['offer_used']."</td></tr>";
ob_flush();
flush();
To the PHP and it didn't work. I don't understand, if I throw an alert, it happens on the fly for every ID, but the html rendering does not.
It may have magically fixed itself because your browser was caching some of the javascript. You should use some developer tools to manually flush the cache of resources for the host you are testing on to avoid old code being subtly used ....

jQuery Ajax - Alternate XML sources for each request

I have two XML sources to retrieve data from. I want to use them alternately per page load. So when someone visits the page the first source will be used, next time the visit the page the other source will be used. Here is the ajax request I am using to get one data source:
$(document).ready(function() {
$.ajax({
type: "GET",
url: "source1.xml", //how do I alternately load two different xml data sources?
dataType: "xml",
success: function(xml) {
var counter = 0
var output = '<li>';
$(xml).find('person').each(function(){
counter++;
var image = $(this).find('image').text();
var name = $(this).find('name').text();
var title = $(this).find('title').text();
var company = $(this).find('company').text();
output = output + '<div><img src=img/' + image + '.jpg />' + '<br /><label><span>' + name + '</span><br />' + title + '<br />' + company + '</label><br /></div>';
if(counter % 3 === 0){
output = output + '</li><li>';
}
});
output = output + '</li>';
$('#update-target ul').html(output);
}
});
});
For extra info, here is how I am alternately loading 2 flash files using PHP:
if(isset($_SESSION['rotation'])){
$picker = $_SESSION['rotation'];
}else{
$picker = rand(0,1);
}
if($picker == 0){
echo '<script type="text/javascript">
var video1 = new SWFObject("somefile1.swf", "p1", "151", "590", "9", "#ffffff");
video1.addParam("wmode","transparent");
video1.write("meh");
</script>';
$_SESSION['rotation'] = ++$picker;
} else {
echo '<script type="text/javascript">
var video1 = new SWFObject("somefile2.swf", "p1", "151", "590", "9", "#ffffff");
video1.addParam("wmode","transparent");
video1.write("meh");
</script>';
$_SESSION['rotation'] = --$picker;
}
I realize I could just stick the jquery document ready code right in there where I have the js calling the flash but it does not seem like a very efficient way of handling this. What is a "best case" way to do this?
You can just use a variable to keep it short, like this:
echo '<script type="text/javascript">var xmlSource = "source1.xml";</script>';
Use that in an if caluse as well, then just reference that in your code:
url: xmlSource,
There are other ways of course, using a cookie (the cookie plugin), putting the text right in the document.ready handler, etc...whichever seems most elegant to you I suppose.
I recommend the variable from the PHP side or a cookie...both of these options allow the document.ready code to stay outside the page in an external script, and not downloaded by the user each time.

Categories