JSON occasionally undefined - how do I check? - javascript

So the JSON object I'm trying to reach sometimes does not exist.
Notice: Undefined index: movies in C:\xampp\htdocs\example\game.php
I'm reaching for it in the Steam API with this code on game.php:
$GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
echo json_encode(array(
'gameTrailer' => $GLOBALS['gameTrailer'],
//+ other variables
));
I'm using AJAX to poke game.php like so on index.php:
function returnGame () {
$.ajax({
url: "game.php",
type: "post",
dataType: 'json',
success: function(data){
console.log(data);
$('#video').removeAttr('src');
///// Game name /////
$('#gameName').html(data.gameName);
/////////////////////
////// Append and load video /////
var videoSrc = data.gameTrailer;
var video_block = $('#video');
if (videoSrc !== null && videoSrc !== undefined) {
video_block.load();
document.querySelector('video').src = videoSrc;
} else {
$("#gameTrailer").find("#gameScreenshot").attr("src", data.gameScreenshot);
}
//////////////////////////////////
},
});
}
When movies is null, the AJAX function does nothing. The video does not change to blank, and the movie title is not updated to something new. When movies is not undefined, it works perfectly.
I can't seem to catch $GLOBALS['gameTrailer'] as undefined and re-iterate or replace with screenshot instead of movie though, not on game.php or index.php. I've tried things like if(empty()) {} and if($GLOBALS['gameTrailer'] == NULL) {}, but even though the error code on game.php tells me that it is undefined, it seems to act like it's not.
Any ideas will be much appreciated. Thanks.
EDIT: Full game.php code:
<?php
if(isset($_POST)) {
fetchGame();
}
function fetchGame() {
////////// ID-picker //////////
$f_contents = file("steam.txt");
$url = $f_contents[mt_rand(0, count($f_contents) - 1)];
$answer = explode('/',$url);
$gameID = $answer[4];
$trimmed = trim($gameID);
////////// Fetch game //////////
$json = file_get_contents('http://store.steampowered.com/api/appdetails?appids='.$trimmed);
$game_json = json_decode($json, true);
////////// Store variables //////////
$GLOBALS['gameName'] = $game_json[$trimmed]['data']['name'];
$GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
$GLOBALS['gameScreenshot'] = $game_json[$trimmed]['data']['screenshots'][0]['path_full'];
$GLOBALS['gameImage'] = $game_json[$trimmed]['data']['header_image'];
$GLOBALS['gameId'] = $trimmed;
$GLOBALS['free'] = $game_json[$trimmed]['data']['is_free'];
$GLOBALS['price'] = $game_json[$trimmed]['data']['price_overview']['final'];
if(!isset($GLOBALS['price']) && ($GLOBALS['gameTrailer'])) {
fetchGame();
}
if ($GLOBALS['free'] === TRUE) {
$GLOBALS['final_price'] = "Free";
} elseif($GLOBALS['free'] === FALSE || $GLOBALS['final_price'] != NULL) {
$GLOBALS['final_price'] = $GLOBALS['price'];
} else {
$GLOBALS['final_price'] = "-";
}
}
////////// Return to AJAX (index.php) //////////
echo
json_encode(array(
'gameName' => $GLOBALS['gameName'],
'gameTrailer' => $GLOBALS['gameTrailer'],
'gameImage' => $GLOBALS['gameImage'],
'gameId' => $GLOBALS['gameId'],
'finalPrice' => $GLOBALS['final_price'],
'gameScreenshot' => $GLOBALS['gameScreenshot']
))
;
?>
It breaks on line 23 ($GLOBALS['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max']; as an undefined index)

Okay, so here is an example update to the code provided going by the comments made on the question.
Notes:
1) Don't use $GLOBALS unless you know what you're doing and why you're using it. In this case, it doesn't appear required. Updated to $game as it's holding game details.
2) You need to check whether something exists before you try and access it. So, the isset you previously had is useless as you've already accessed a non-existing array item. Removed that check.
3) Recursion is good, but again, you need to know what you're doing, and why you're using it. I suspect this was unintentional anyway but was removed as part of 2.
4) You state that having a video (and price by the looks of it) is a requirement for this function, so you should check that up front. Note that the first thing after getting the ID, is to see if there's a video. Why do work just to find we can't use it?
5) You want to try a different game if there is no video, so we wrap the check and assignments in a loop, and continue if the video isn't there. Note that you might want to restrict this to n number of tries otherwise you might end up waiting ages for your script to find a game that has a video, but that's for you to decide.
<?php
if(isset($_POST)) {
fetchGame();
}
function fetchGame() {
$gameFound = false;
while(!$gameFound) {
////////// ID-picker //////////
$f_contents = file("steam.txt");
$url = $f_contents[mt_rand(0, count($f_contents) - 1)];
$answer = explode('/',$url);
$gameID = $answer[4];
$trimmed = trim($gameID);
////////// Fetch game //////////
$json = file_get_contents('http://store.steampowered.com/api/appdetails?appids='.$trimmed);
$game_json = json_decode($json, true);
if(!isset($game_json[$trimmed]['data']['movies'][0]['webm']['max']) || !isset($game_json[$trimmed]['data']['price_overview']['final'])) {
continue;
}
$gameFound = true;
////////// Store variables //////////
$game['gameName'] = $game_json[$trimmed]['data']['name'];
$game['gameTrailer'] = $game_json[$trimmed]['data']['movies'][0]['webm']['max'];
$game['gameScreenshot'] = $game_json[$trimmed]['data']['screenshots'][0]['path_full'];
$game['gameImage'] = $game_json[$trimmed]['data']['header_image'];
$game['gameId'] = $trimmed;
$game['free'] = $game_json[$trimmed]['data']['is_free'];
$game['price'] = $game_json[$trimmed]['data']['price_overview']['final'];
if ($game['free'] === TRUE) {
$game['final_price'] = "Free";
} elseif($game['free'] === FALSE || $game['final_price'] != NULL) {
$game['final_price'] = $game['price'];
} else {
$game['final_price'] = "-";
}
}
}
////////// Return to AJAX (index.php) //////////
echo
json_encode(array(
'gameName' => $game['gameName'],
'gameTrailer' => $game['gameTrailer'],
'gameImage' => $game['gameImage'],
'gameId' => $game['gameId'],
'finalPrice' => $game['final_price'],
'gameScreenshot' => $game['gameScreenshot']
));
?>
Note this code is untested, but I hope gives you an idea of how to proceed.

Related

Problems with setting a data attribute using vanilla javascript

I've been working with a set of data that is returned from a fetch call to a Lucee coldfusion server. The data returned is a structure that looks like this:
{success: true, new_case_number: caseno}
This is how everything starts on the Javascript side. I've setup a submit event handler for the form element using form.addeventlistener('submit', inquirySubmit). This is what that looks like:
function inquirySubmit(){
event.preventDefault();
var data = [this.lastname.value, this.caseno.value, this.id.value];
fetch(`../CFC/flowstatus.cfc?method=setDebtorInfo&action=inquiry&trusteeID=${slush}&values=${data}`, {
method: 'post'
})
.then( res => res.json())
.then( (data)=>{
if( data.SUCCESS == true ){
setNewValues(this.lastname.value, data.NEW_CASE_NUMBER)
background.style.transform = 'scaleY(0)';
setTimeout( ()=>{
inquiryEditForm.reset();
inquiryEditForm.display = 'none';
}, 1000 )
}
if( data.SUCCESS == false) alert('Argh!')
})
} // END FUNCTION
if the data.SUCCESS variable is set to true I use the setNewValues function:
function setNewValues(lastname, caseno){
console.log(`Lastname: ${lastname}\n Caseno: ${caseno}.`)
var dm = document.querySelector('.debtor-main');
var cn = dm.querySelectorAll('div');
cn.forEach( (div)=>{
if( div.dataset.caseNo == caseno){
div.setAttribute('data-case-no', caseno )
var span_lastname = div.querySelector('#lastname');
var span_caseno = div.querySelector('span[id=caseno]');
span_lastname.innerHTML = lastname;
span_lastname.setAttribute('data-case-no', caseno );
span_caseno.innerHTML = caseno;
span_caseno.setAttribute('data-case-no', caseno );
}
})
} // END FUNCTION
I've added some console.log bits in there to make sure I was getting the right values and they are good. As you can see I'm changing the innerHTML values of some span elements to reflect the changes that the user has typed in. The variable span_lastname gets reset no problem. But neither the data-case-no attributes nor the span_caseno.innerHTML respond to the setAttribute('data-case-no', caseno) call. The thing that's really irritating is that I know I'm accessing the right element with the span_caseno variable because I can effect the style attribute like so:
span_caseno.style.opacity = 0;
And it works.
If anyone has some suggestions it would be very helpful. I'd be happy to change the code up completely, so fire away.
Try using:
span_lastname.dataset.caseNo = caseno;
span_caseno.dataset.caseNo = caseno;
Instead of using setAttribute.
function setNewValues(lastname, caseno){
console.log(`Lastname: ${lastname}\n Caseno: ${caseno}.`)
var dm = document.querySelector('.debtor-main');
var cn = dm.querySelectorAll('div');
Array.from(cn).map( (div)=>{
if( div.dataset.caseNo == caseno){
div.setAttribute('data-case-no', caseno )
var span_lastname = div.querySelector('#lastname');
var span_caseno = div.querySelector('span[id=caseno]');
span_lastname.innerHTML = lastname;
span_lastname.setAttribute('data-case-no', caseno );
span_caseno.innerHTML = caseno;
span_caseno.setAttribute('data-case-no', caseno );
}
})
} // END FUNCTION

Array output problem at Webscraping with DOMparser

I'm facing some output trouble at the second part of my codes.
function getSiteContent($url)
{
$html = cache()->rememberForever($url, function () use ($url) {
return file_get_contents($url);
});
$parser = new \DOMDocument();
#$parser->loadHTML($html);
return $parser;
}
libxml_use_internal_errors(true);
$url = 'https://sumai.tokyu-land.co.jp/osaka';
$parser = getSiteContent($url);
$allDivs =[];
$allDivs = $parser->getElementsByTagName('div');
foreach ($allDivs as $div) {
if ($div->getAttribute('class') == 'p-articlelist-content-right') {
$allLinks = $div->getElementsByTagName('a');
foreach ($allLinks as $a) {
$getlinks[] = $a->getAttribute('href');
}
}
}
var_dump($getlinks);
At this var_dump I can see links that I scraped. No problem 'till here. And one more time. I want to go into those links. That's why I wrote the codes right below.
getSiteContent($getlinks);
$link = [];
$siteler = [];
foreach ($siteler as $site) {
if($site == 'https://sumai.tokyu-land.co.jp'){
$site = $getlinks->getElementsByTagName('div');
foreach ($site as $links) {
if($links->getAttribute('class') == 'pc_hnavi'){
$linker = $links->getElementsByTagName('a');
foreach ($linker as $a) {
$link = $a->getAttribute('href');
}
}
}
}
}
var_dump($link);
When I var_dump it. It says Array 0
I didn't understand why it doesn't go in those links with foreach
My codes are wrong? What am I missing here? Any idea for this?
Thank you helping me out.
As I said in the comments $siteler is empty when you try to loop through it, but there are a couple more problems:
First your code will only trigger once at most, when the link is exactly 'https://sumai.tokyu-land.co.jp' and I'm not sure that's what you want.
You are calling DOM functions on an array.
Only seem to care about links inside 'div' tags.
You redefine the $link variable on each loop, so the final result will be just one link.
This is the fixed code:
$link = [];
foreach ($getlinks as $site) {
// Any link in the domain, not just the homepage
if(strpos($site, 'https://sumai.tokyu-land.co.jp') === 0) {
$dom = getSiteContent($site);
$divs = $dom->getElementsByTagName('div');
foreach ($divs as $div) {
// Can have more than one class
$attrs = explode(' ', $div->getAttribute('class'));
if(in_array('pc_hnavi', $attrs)) {
$linker = $div->getElementsByTagName('a');
foreach ($linker as $a) {
// Add to the array
$link[] = $a->getAttribute('href');
}
}
}
}
}
However this doesn't check if the link already exists in the array and has the potential to process the same links over and over. I'd strongly suggest to use an existing crawler.
From the comments, turns out that pc_hnavi is an id and not a class and you are interested in the first link only. You can access that element directly without iterating the elements:
foreach ($getlinks as $site) {
// Any link in the domain, not just the homepage
if(strpos($site, 'https://sumai.tokyu-land.co.jp') === 0) {
$dom = getSiteContent($site);
$div = $dom->getElementById('pc_hnavi');
if ($div != null) {
$links = $div->getElementsByTagName('a');
if ($links->length > 0) {
$a = $links->item(0);
$link[] = $a->getAttribute('href');
}
}
}
}
It looks like your problem is here:
...
$siteler = []; // $siteler is set to an empty array ...
foreach ($siteler as $site) { // then you loop through the empty array which does nothing ...
...
}
...
Fixing that should get you started.

Call a function as long as the condition is not met

Let me explain on what I'm doing here
I've been trying to build a poll app in angularjs and have a randomized randomPollCode which (of course) consists of random letters and numbers that I want to be the unique identifier of my polls to call them specifically in the future. So what I'm trying to accomplish is to check my database if the randomPollCode generated is already in the database.
Here's the code:
//checkPollCodeIfAvail checks if the randomPollCode already exists in the db
pollCodeStatus = pollFactory.checkPollCodeIfAvail(randomPollCode)
.then(function (response) {
//if there's no row with the same randomPollCode
if (response == "0") {
pollCodeAvail = true;
proceed();
}else{
//what should I put in here?
}
console.log(response)
});
I've been trying to do a do/while loop in the else part but it will just loop endlessly and call the function over and over again.
EDIT: Added some code
The above code will call this method here:
factory.checkPollCodeIfAvail = function(x){
code = x;
return $http({
method: 'POST',
data: {
'action' : 'checkPollCode',
'pollCode' : code
},
url: 'http://localhost/poll/api.php',
transformRequest:function(obj) {
//transform header query into 'myVar1=var1Value&myVar2=var2Value'
var str=[];
for(var p in obj){
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]))
}
console.log(str.join("&"));
return str.join("&");
},
headers:{'Content-Type':'application/x-www-form-urlencoded'}
}).then(function(response){
var i = response.data.message.toString();
console.log(i);
return i;
});
};
AND the above code will code this method here:
switch ($_POST['action']) {
case 'checkPollCode':
$sql = "SELECT * FROM polls WHERE pollCode = :pollcode";
$stmt = $db_con->prepare($sql);
$stmt->bindParam(":pollcode", $checkPollCode);
$stmt->execute();
if($stmt->rowCount() >= 0){
$count = $stmt->rowCount();
$arr = array();
$arr['message'] = (string)$count;
echo json_encode($arr);
}
break;
}
There's no problem for me returning data from the server. It's just I just want to make sure that there's no duplicate pollCode in my database.
Thank you for anyone that can help me.

PS 1.6 Module trigger event on Ajax Add to cart

I've been studying how PrestaShop modules work lately and it would be great if someone could point me in the right direction.
I want to trigger an event (javascript method to be exact, let's call it "MyShop") that would get all the product details in it.
I have some older code but either it was working with older version of PS either it's only for normal add to cart and not ajax.
The issue is that it doesn't even get triggered at all after pressing "add to cart" button, it's actually a piece of code from Google Analytics module.
Here is a piece of modified code from my module's main .php file that is supposed to get triggered on the add to cart, it's using "hookActionCartSave()" but I am not sure if that is still available in 1.6 or got replaced by something else or whether it just simply doesn't work with ajax and I should look elsewhere?
/**
* hook save cart event to implement addtocart and remove from cart functionality
*/
public function hookActionCartSave()
{
if (!isset($this->context->cart))
return;
$cart = array(
'controller' => Tools::getValue('controller'),
'addAction' => Tools::getValue('add') ? 'add' : '',
'removeAction' => Tools::getValue('delete') ? 'delete' : '',
'extraAction' => Tools::getValue('op'),
'qty' => (int)Tools::getValue('qty', 1)
);
$cart_products = $this->context->cart->getProducts();
if (isset($cart_products) && count($cart_products))
foreach ($cart_products as $cart_product)
if ($cart_product['id_product'] == Tools::getValue('id_product'))
$add_product = $cart_product;
if ($cart['removeAction'] == 'delete')
{
$add_product_object = new Product((int)Tools::getValue('id_product'), true, (int)Configuration::get('PS_LANG_DEFAULT'));
if (Validate::isLoadedObject($add_product_object))
{
$add_product['name'] = $add_product_object->name;
$add_product['manufacturer_name'] = $add_product_object->manufacturer_name;
$add_product['category'] = $add_product_object->category;
$add_product['reference'] = $add_product_object->reference;
$add_product['link_rewrite'] = $add_product_object->link_rewrite;
$add_product['link'] = $add_product_object->link_rewrite;
$add_product['price'] = $add_product_object->price;
$add_product['ean13'] = $add_product_object->ean13;
$add_product['id_product'] = Tools::getValue('id_product');
$add_product['id_category_default'] = $add_product_object->id_category_default;
$add_product['out_of_stock'] = $add_product_object->out_of_stock;
$add_product = Product::getProductProperties((int)Configuration::get('PS_LANG_DEFAULT'), $add_product);
}
}
if (isset($add_product) && !in_array((int)Tools::getValue('id_product'), self::$products))
{
self::$products[] = (int)Tools::getValue('id_product');
$ga_products = $this->wrapProduct($add_product, $cart, 0, true);
if (array_key_exists('id_product_attribute', $ga_products) && $ga_products['id_product_attribute'] != '' && $ga_products['id_product_attribute'] != 0)
$id_product = $ga_products['id_product_attribute'];
else
$id_product = Tools::getValue('id_product');
if (isset($this->context->cookie->MyShop_cart))
$MyShop_cart = unserialize($this->context->cookie->MyShop_cart);
else
$MyShop_cart = array();
if ($cart['removeAction'] == 'delete')
$ga_products['quantity'] = -1;
elseif ($cart['extraAction'] == 'down')
{
if (array_key_exists($id_product, $MyShop_cart))
$ga_products['quantity'] = $MyShop_cart[$id_product]['quantity'] - $cart['qty'];
else
$ga_products['quantity'] = $cart['qty'] * -1;
}
elseif (Tools::getValue('step') <= 0) // Sometimes cartsave is called in checkout
{
if (array_key_exists($id_product, $MyShop_cart))
$ga_products['quantity'] = $MyShop_cart[$id_product]['quantity'] + $cart['qty'];
}
$MyShop_cart[$id_product] = $ga_products;
$this->context->cookie->MyShop_cart = serialize($MyShop_cart);
$this->didCartChange = 1;
}
}
I know that regarding what I am looking for a lot is handled in blockcart/ajax-cart.js and controllers/front/CartController.php but I am not precisely sure where or what to look for and this way I was hoping someone will lead me to a proper direction or save me some time on searching.
I also assume that regarding the javascript potion I have to modify the template itself, this is a piece of code from my module's header.tpl:
var MyShop_blockcart_log = function(json) {
var products = json.products;
var product;
var ps = [];
var p;
for(var i=0; i<products.length; i++) {
product = products[i];
p = {};
p.id = product.id;
p.link = product.link;
p.imageUrl = product.id_image.replace("medium_default", "large_default");
p.quantity = product.quantity;
p.name = product.name;
p.price = "{$currency->sign} " + (parseInt(product.price_float) / product.quantity).toFixed(2);
ps.push(p);
}
MyShop("log", "product", "cart", ps);
}
That code does not cause any errors, it just doesn't get triggered after adding products to the cart and it should.
Do I have to bind it to the add to cart button via my header.tpl file for example? And if yes then how could I do it?
Thanks in advance,
Cheers.
The hookActionCartSave only executes on cart->add() and cart->update(). But when CartController updates/adds a product, if the cart already exists for that customer, it won't executes neither one of them.
I would recommend using the actionBeforeCartUpdateQty:
Hook::exec('actionBeforeCartUpdateQty', array(
'cart' => $this,
'product' => $product,
'id_product_attribute' => $id_product_attribute,
'id_customization' => $id_customization,
'quantity' => $quantity,
'operator' => $operator,
'id_address_delivery' => $id_address_delivery,
'shop' => $shop,
'auto_add_cart_rule' => $auto_add_cart_rule,
));
It might suit your needs. Or look for another hook. In the last case scenario, you could override the CartController->postProcess and check if it's trying to add/remove products. I used this override to let the user add the maximum amount available to cart. Example, if stock is 5, and user tries to add 6, it will add 5 and not send an error. It also checks for product used in packs. If same product is in 2 pack, user can't order max stock of both packs.

convert from json to array

I am trying to get data to display in a table. I don't know what I am doing wrong, but when I get the data from my page it is an array of single characters. I could parse this myself but would prefer to know what I am doing wrong.
I have this php to get the data:
function BuildViewerCombo($autocomplete) {
$wholeNumberCombo = array();
$dbhandle = DB_Connect();
$result = QueryForward($dbhandle, SQL_WholeNumbersPartial($autocomplete));
while($wholeNumber = sqlsrv_fetch_array($result))
{
$wholeNumberCombo[] = array($wholeNumber['DocumentNbr'] => 'Number', $wholeNumber['DocumentRevision'] => 'Revision');
}
//close the connection
sqlsrv_close($dbhandle);
return $wholeNumberCombo;
}
Which is called from this page
<?PHP
include "Scripts/DB_Functions.php5" ;
include "Scripts/SQL_Viewer.php5" ;
$wholeNumber = $_GET['wholeNumber'];
echo json_encode(BuildViewerCombo($wholeNumber));
?>
Which gets loaded from this function
function toggleDropdown()
{
var wholeNumberData
var wholeNumber = document.getElementById('WholeNumber').value;
if (wholeNumber != '') {
wholeNumberData = GetData('wholeNumber', wholeNumber);
var table = document.getElementById("wholeNumberDropdown");
alert ('WN = ' + wholeNumberData.length);
alert (wholeNumberData);
for (var i in wholeNumberData) {
alert(wholeNumberData[i]);
}
}
else {
alert("Please enter a whole number.");
}
}
By calling this function:
function GetData(getType, param) {
var http = new XMLHttpRequest();
http.open("GET", 'ViewerWholeNumbers.php?wholeNumber=' + param, false);
http.setRequestHeader("Content-type","application/json");
http.onload = function() {
}
http.send('wholeNumber=' + param);
return http.responseText;
}
The data that gets returned is:
[{"SS3999":"Number","A":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","":"Revision"},{"SS3999":"Number","11":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","11":"Revision"},{"SS3999":"Number","A":"Revision"},
{"SS3999":"Number","":"Revision"}]
But alert ('WN = ' + wholeNumberData.length); returns 546 and when I try to loop through the array I get a single character for each element instead of the values.
First off, your associative array is flipped. You need to change
array($wholeNumber['DocumentNbr'] => 'Number', $wholeNumber['DocumentRevision'] => 'Revision');
to
array('Number' => $wholeNumber['DocumentNbr'], 'Revision' => $wholeNumber['DocumentRevision']);
You need that in order to access the elements of the JSON. Then, in your loop, you would use wholeNumberData[i].Number to get the number and wholeNumberData[i].Revision to get the revision.
Update:
As #jeroen pointed out, you need JSON.parse() to convert the return string to JSON. In your GetData function replace your return with this:
return JSON.parse(http.responseText);

Categories

Resources