I need to write a conditional that checked each image value and if its empty displays a stock photo 'selfie.jpg' and if it is not then display whatever is inside of it.
I know how to access it beat.officers[0].image. what I don't know is how to make the program check through the length of officers for each items image value, check if its empty and then display a photo based on the results of that check.
pls help its for a test.
A image of the Json object I am trying to work with
const policeData = [
{
beat:
{
name: 'Portishead',
latLong: ' ',
introText: 'Contact your local policing team, find opportunities to meet the team and view or contribute to community policing priorities for your area.',
officers: [
{
name: 'Trevor Dyson',
role: 'Neighbourhood Police Team Sergeant',
image: ''
},
{
name: 'Kirsten Karcher',
role: 'Police Community Support Officer',
image: 'kkarcher.jpg'
},
{
name: 'Bill Hoover',
role: 'Police Community Support Officer',
image: ''
},
{
name: 'Andrew Henry',
role: 'Partnership Support Officer',
image: ''
}
],
priorities: [
{
title: 'Road Safety Week',
updated: '18 November 2019',
path: '/road-safety-week/'
},
{
title: 'Community SpeedWatch',
updated: '14 August 2019',
path: '/community-speedwatch/'
},
{
title: 'Mopeds using footpaths and speeding vehicles',
updated: '04 September 2019',
path: '/mopeds-using-footpaths-and-speeding-vehicles/'
}
]
}
}];
So here is my template which is functional. As you can see though its not dynamic and I tried to input the conditional as a function with an if statement but its just not working. I did consider trying the turnery (condition : if yes : if no) but I struggled with that too.
Some of the image values are empty you see? Ultimately, I am trying to make it go through each object and check its image value and then run the conditional.
function kk(police) {
officers = police.beat.officers.length;
return `
<div class=person>
<img class="pol-photo" src = "${photoO(police.beat.officers[0])}"
<h2 class ="pol-name">${police.beat.officers[1].name}</h2>
<p> ${police.beat.officers[1].role}</p>
</div>
`
}
function photoO(pol) {
if (pol == '' ) {
return 'officer-profile.jpg'
} else {
return 'kkarcher.jpg'
}
}
You can use the functions from below to get the correct output. One function will return the HTML for just one officer while the other will return the HTML of all of them. You can test it below.
const policeData = [
{
beat:
{
name: 'Portishead',
latLong: ' ',
introText: 'Contact your local policing team, find opportunities to meet the team and view or contribute to community policing priorities for your area.',
officers: [
{
name: 'Trevor Dyson',
role: 'Neighbourhood Police Team Sergeant',
image: ''
},
{
name: 'Kirsten Karcher',
role: 'Police Community Support Officer',
image: 'kkarcher.jpg'
},
{
name: 'Bill Hoover',
role: 'Police Community Support Officer',
image: ''
},
{
name: 'Andrew Henry',
role: 'Partnership Support Officer',
image: ''
}
],
priorities: [
{
title: 'Road Safety Week',
updated: '18 November 2019',
path: '/road-safety-week/'
},
{
title: 'Community SpeedWatch',
updated: '14 August 2019',
path: '/community-speedwatch/'
},
{
title: 'Mopeds using footpaths and speeding vehicles',
updated: '04 September 2019',
path: '/mopeds-using-footpaths-and-speeding-vehicles/'
}
]
}
}];
// helper function to check if value is empty
function existsAndNotEmpty(value) {
if (typeof value != 'undefined' && value.length > 0) {
return true;
}
return false;
}
function getOfficerHTML(officer) {
let result = "";
if( existsAndNotEmpty(officer.image) ) {
result += '<img class="pol-photo" src = "' + officer.image + '" />';
} else {
result += '<img class="pol-photo" src = "officer-profile.jpg" />';
}
if( existsAndNotEmpty(officer.name) ) {
result += '<h2 class ="pol-name">' + officer.name + '</h2>';
} else {
result += '<h2 class ="pol-name">Unknown officer</h2>';
}
if( existsAndNotEmpty(officer.role) ) {
result += '<p>' + officer.role + '</p>';
} else {
result += '<p>Unknown role</p>';
}
return result;
}
function getAllOfficerHTML() {
let result = "";
let officerLength = policeData[0].beat.officers.length;
let officers = policeData[0].beat.officers;
for(var i=0; i < officerLength; i++){
result += getOfficerHTML(officers[i]);
}
return result;
}
// Now you can use it like this to print a single officer
var singleOfficer = getOfficerHTML(policeData[0].beat.officers[1]);
console.log(singleOfficer);
// or like this to get all ooficers at once
var allOfficers = getAllOfficerHTML();
console.log(allOfficers);
Related
Hi to every one reading this. I am struggling with a PDF.js problem. I am using this library: https://github.com/edisonneza/jspdf-invoice-template to render a PDF with data that I am getting from an internal axios route that returns orders. This orders are listed with a checkbox, for the orders checked I generate a new array with the objects of the different orders checked.
Up to this I was doing fine, but the next thing I need is to generate this PDFs. I got it to work rendering one single pdf with the data order, but i would like to generete a PDF with (N) numbers of pages, using the checked orders to print with a button.
Below are the blocks of the code that i wrote.
printAllbtn.addEventListener('click',function(){
try {
if(ordersSelectedToPrint.length \> 1){
console.log(ordersSelectedToPrint);
for (let orderPrint of ordersSelectedToPrint) {
let pdfObject = jsPDFInvoiceTemplate.default(props);
console.log( 'object created' + pdfObject + orderPrint)
var props = {
outputType: jsPDFInvoiceTemplate.OutputType.Save,
returnJsPDFDocObject: true,
fileName: "remito",
orientationLandscape: false,
compress: true,
business: {
name: "Isidorito",
address: "San Pedro, Buenos",
phone: "(3329) 069 11 11 111",
email: "contacto#isidorito.com",
website: "www.isidorito.com.ar/nosotros",
},
contact: {
label: "Remito dirigito a:",
name: `${orderPrint.cliente.dueño}`,
address:`${orderPrint.cliente.direccion}`,
phone: `${orderPrint.cliente.telefono1}`,
email: `${orderPrint.cliente.correo}`,
},
invoice: {
label: "Pedido #",
num: 19,
invDate: `${orderPrint.createdAt}`,
invGenDate: `28/10/2022`,
headerBorder: false,
tableBodyBorder: false,
header: [
{
title: "#",
style: {
width: 10
}
},
{
title: "Productos descripción",
style: {
width: 70
}
},
{
title: "Cantidad ",
style: {
width:20
}
},
{ title: "Por Unidad",
style:{width:30}},
// { title: "Cantidad"},
{ title: "Por tot",
style:{
width:30
}},
{ title: "Total",
style:{
width:30
}}
],
table: Array.from(orderPrint.productosPedidosNombre).forEach(function(productoIm, index){[
index + 1,
`${productoIm.nombre} - ${productoIm.marca} - ${productoIm.presentacion}`,
`${productoIm.cantidad}`,
`${productoIm.cantidad}`,
`${productoIm.cantidad}`,
`${productoIm.cantidad}`,
]}),
invDescLabel: "Cliente:",
invDesc: `${orderPrint.cliente.nombreLocal}`,
},
footer: {
text: "Este remito generado digitalmente es valido para el pedido realizado",
},
pageEnable: true,
pageLabel: "Page ",
};
} } } catch (error) { console.log(error); }
});
The first note is that "orderPrint.productosPedidosNombre" is an array of products of the order. In the example from the documentation its represented in this way.
table: Array.from(Array(10), (item, index)=>([
index + 1,
"There are many variations ",
"Lorem Ipsum is simply dummy text dummy text ",
200.5,
4.5,
"m2",
400.5
])),
And the way I generate the PDF is:
let pdfObject = jsPDFInvoiceTemplate.default(props);
First I would like to know if it is possible the loops and iteration to generate this type of single file with N number of order pages, and each page with different data. It's possible with this library.
Thanks you. It's my second question I've asked in StackOverflow, so I welcome the feedback on the how to ask in stack overflow.
So I'm trying to use a single sheet as a price db to update prices in WooCommerce through the Woo API, using fetch.
It works, my problem is that it apparently works depending on the size of the dataset? I'm not sure because I can't understand the error.
UPDATED CODE
function getDataloopwoo() {
const ck = 'ck_fd0992917fbbb0464d4146ad5861f51adcb36369';
const cs = 'cs_6f8061efce415355fb6cac520bd1506ad126578a';
const website = 'https://www.atopems-desarrollo.com.ar';
const optionsGet =
{
'method': 'GET',
'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
'muteHttpExceptions': true,
};
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('PreciosBULK');
const codigos = sheet.getRange('A2:A').getValues();
const precios = sheet.getRange('B2:B').getValues();
const data = codigos.map(function(codigos, indice) {
return {
sku: codigos[0],
price: precios[indice][0]
}
})
const container = [];
var surl = website + '/wp-json/wc/v3/products?consumer_key=' + ck + '&consumer_secret=' + cs + '&per_page=100' + '&orderby=id' + '&order=asc' + '&status=publish' + '&page=1';
var url = surl
Logger.log(url)
var result = UrlFetchApp.fetch(url, optionsGet);
var headers = result.getAllHeaders();
var total_pages = 45;
var pages_count = 0;
while (pages_count < total_pages) {
if (result.getResponseCode() == 200) {
var wooProducts = JSON.parse(result.getContentText());
//Logger.log(result.getContentText());
}
for (var i = 0; i < wooProducts.length; i++) {
//Logger.log(i);
container.push({
sku: wooProducts[i]['sku'],
id: wooProducts[i]['id'],
price: wooProducts[i]['price']
});
}
pages_count++;
if (pages_count < total_pages) {
var surl = website + '/wp-json/wc/v3/products?consumer_key=' + ck + '&consumer_secret=' + cs + '&per_page=100' + '&orderby=id' + '&order=asc' + '&status=publish' + '&page=' + (pages_count + 1);
var url = surl
var result = UrlFetchApp.fetch(url, optionsGet);
Logger.log(url);
}
}
var data_obj = {}
for (let obj of data)
data_obj[obj.sku] = {'price': obj.price};
console.log(data_obj);
var container_obj = {}
for (let obj of container)
container_obj[obj.sku] = {'price': obj.price, 'id': obj.id};
console.log(container_obj);
const output = [];
for (let sku in container_obj) {
let data_subObj = data_obj[sku];
let container_subObj = container_obj[sku];
if (data_subObj.price > container_subObj.price) {
output.push({'id':container_subObj.id, 'regular_price':data_subObj.price});
}
}
console.log(output);
var temporary, chunk = 100;
for (let i = 0;i < output.length; i += chunk) {
temporary = output.slice(i, i + chunk);
var payloadUp = {
update: temporary
}
var headPost =
{
'method' : 'POST',
'contentType': 'application/json',
'payload': JSON.stringify(payloadUp)
};
console.log(payloadUp);
var urlPost = website + '/wp-json/wc/v3/products/batch?consumer_key=' + ck + '&consumer_secret=' + cs;
var result = UrlFetchApp.fetch(urlPost, headPost);
console.log(urlPost);
if (result.getResponseCode() == 200) {
console.log(result.getContentText());
};
}
}
I use the var headers to get all headers but since I'm testing ATM I don't use it. So if I get around 15-20 products from WooCoommerce everything works like a charm, I get all product data, create a new array with sku, id and price. Then compare that array with an array from my sheets with the updated price value and then push sku, id and updated price to a new array and POST that array to woocommerce batch update. Works fine, if I try to process more I get this error:
TypeError: Cannot read property 'price' of undefined
I'm really wracking my brains mostly because I'm a total novice in JS.
I'll post the logs,
Logger.log(url);
https://atopems.com/wp-json/wc/v3/products?consumer_key=ck_xxx&consumer_secret=cs_xxx&per_page=100&orderby=id&order=asc&status=publish&page=51
console.log(data_obj);
Logging output too large. Truncating output. { '200': { price: 299.98 },
'201': { price: 156.9 },
'202': { price: 112.05 },
'203': { price: 100.58 },
'204': { price: 126.33 },
'205': { price: 126.53 },
'206': { price: 2858.42 },
'207': { price: 2336.79 },
'208': { price: 401.25 },
'209': { price: 378.32 },
'210': { price: 282.78 },
'211': { price: 252.21 },
'212': { price: 292.34 },
'213': { price: 309.53 },
'214': { price: 385.96 },
'215': { price: 554.1 },
console.log(container_obj);
Logging output too large. Truncating output. { '60026': { price: '2319.6', id: 24942 },
'60032': { price: '4050.7', id: 24943 },
'60033': { price: '4050.7', id: 24944 },
'60119': { price: '7195.72', id: 24945 },
BR9010: { price: '984.5', id: 24067 },
BR9013: { price: '1744.32', id: 24068 },
BR9014: { price: '1869.03', id: 24069 },
BR9015: { price: '1869.03', id: 24070 },
BR9016: { price: '984.5', id: 24071 },
BR9017: { price: '747.66', id: 24072 },
BR9026: { price: '664.52', id: 24073 },
BR9037: { price: '830.62', id: 24074 },
BR9042: { price: '830.62', id: 24075 },
BR9043: { price: '747.66', id: 24076 },
BR9048: { price: '1204.44', id: 24077 },
BR9049: { price: '955.23', id: 24078 },
BR9050: { price: '955.23', id: 24079 },
BR9052: { price: '1079.9', id: 24080 },
BR9055: { price: '955.23', id: 24081 },
BR9056: { price: '1266.63', id: 24082 },
BR9059: { price: '955.23', id: 24083 },
BR9067: { price: '830.62', id: 24084 },
BR9068: { price: '1349.13', id: 24085 }
The exact error
17:07:38 Error
TypeError: Cannot read property 'price' of undefined
getDataloopwoo # JSONsheet.gs:63
The sheet in question, in case anyone wants to see the type of data I'm working with.
const data = codigos.map etc
uses 2 variables, SKU and PRICE, which are column A and B respectively in the sheet as simple objects.
EDIT:
Ok, Test sheet that can be copied with CK and CS Keys to a testing WooCommerce site.
https://docs.google.com/spreadsheets/d/14afFyj1geaNCWt_e4DE9S41wlgepWAtasK2z5_u1hdc/edit?usp=sharing
If run as is it can be reproduced without doing anything else.
Tried with 20 pages it works, with 45 it doesn't.
I'm not sure what more I could do to make it reproducible.
I legit don't understand what could be the root of the problem.
Modification points:
In your situation, it seems that the values of sku of container is not existing in the values of sku of data_obj. I thought that the reason for your issue might be due to this.
As a script for checking this, you can use const res = container.filter(e => !data_obj[e.sku]) for your script. In this case, [ { sku: 'L4943-0ULT', id: 3195, price: '5083.33' } ] is returned. When this value is searched from your sample Spreadsheet, l4943-0ult is found. In this case, the character case is different. By this, your issue occurs. I resulted in the reason of your issue is due to this.
When this issue was removed, how about the following modification?
From:
data_obj[obj.sku] = {'price': obj.price};
To:
data_obj[isNaN(obj.sku) ? obj.sku.toUpperCase() : obj.sku] = {'price': obj.price};
And,
From:
container_obj[obj.sku] = {'price': obj.price, 'id': obj.id};
To:
container_obj[isNaN(obj.sku) ? obj.sku.toUpperCase() : obj.sku] = { 'price': obj.price, 'id': obj.id };
And also, in order to avoid no keys in the if statement, how about adding the following modification?
From:
if (data_subObj.price > container_subObj.price) {
To:
if (data_subObj && data_subObj.price > container_subObj.price) {
In future I have many if condition, any idea to shorten the if condition for (Render Badge items)?
Today I just only have 4 item if in the future I have 20 or maybe 100 item, is it i need to code the if for 20 or 100 times?
I have tried many method, but I don't know how to make it.
Render Dynamic List
const medals = productItem.goldmedal || productItem.newitem || productItem.freedelivery;
if (medals) {
const iconBadge = $("<ul>", { class: 'icons' });
function createMedal(src, text) {
const badge =
$("<li>", { class: 'icon' })
.append($('<a>', { class: 'tpsTooltip skeleton_hide', href: '###', 'data-tippy-content': text })
.append($('<img>', { src: src, alt: text })))
.append($('<div>', { class: 'pl-placeholder_skeleton pl-placeholder_liIcon' }));
iconBadge.append(badge);
}
createFeatureIcon.append(iconBadge);
//Render Badge items (Below is the if condition code)
if (productItem.goldmedal) {
createMedal(plSettings.goldMetalSrc, plSettings.goldMetalText)
}
if (productItem.newitem) {
createMedal(plSettings.newItemSrc, plSettings.newItemText)
}
if (productItem.newshop) {
createMedal(plSettings.newShopSrc, plSettings.newShopText)
}
if (productItem.freedelivery) {
createMedal(plSettings.freeDeliverySrc, plSettings.freeDeliveryText)
}
}
Settings
//Settings
var plSettings = $.extend({
mainClass: 'item-wrapper',
itemWrapperClass: 'item ripple-effect ripple-joya itemShadowLight',
goldMetalSrc: '/img/tps/gold.png',
goldMetalText: 'Gold Medal sellers stand out from millions of sellers, bringing more trust and peace of mind to your shopping experience',
newItemSrc: '/img/tps/new.png',
newItemText: 'New item',
sellermedalSrc: '/img/tps/seller.png',
sellermedalText: 'Top Seller',
newShopSrc: '/img/tps/newshop.png',
newShopText: 'New Shop In Joyacart',
freeDeliverySrc: '/img/tps/freedelivery.png',
freeDeliveryText: 'Free Delivery'
});
example data is below:
var data = {
productList: [
{
id: "62276197-6059-4c21-9b40-c5b1d277e85d",
link: "javascript:void(0)",
imgurl: "/img/upload/png/joyacart_000001_12032019.png",
text: 'Product 001',
goldmedal: false,
newitem: true,
newshop: true,
freedelivery: true
},
{
id: "59de8216-052d-4e51-9f7d-7e96642ded62",
link: "javascript:void(0)",
imgurl: "/img/upload/png/joyacart_000002_12032019.png",
text: 'Product 002',
goldmedal: true,
newitem: false,
newshop: true,
freedelivery: true
}]
}
So you have a product item that looks like this(I assume you can't change that):
{
id: "62276197-6059-4c21-9b40-c5b1d277e85d",
link: "javascript:void(0)",
imgurl: "/img/upload/png/joyacart_000001_12032019.png",
text: 'Product 001',
goldmedal: false,
newitem: true,
newshop: true,
freedelivery: true
},
Let's create an array of keys from that object that tell you if you should show a medal for it:
const medalItems = ['goldmedal', 'newitem', 'newshop', 'freedelivery'];
Now instead of multiple if statements you can iterate over these keys and call createMedal for all these that are true in productItem. Passing that medal key(eg. "goldmedal" or "freedelivery") to createMedal function
for (const medal of medalItems) {
if(productItem[medal]) {
createMedal(medal);
}
}
Now in createMedal you can get src and text based on that medal key, but you'll need to adjust settings accordingly (eg. src for goldmedal should be under plSettings.goldmedalSrc)
function createMedal(medal) {
const src = plSettings[medal + "Src"];
const text = plSettings[medal + "Text"];
...
}
Not perfect because you'll need to keep plSettings in sync with productItems but it should work with your current data structures. And all you need to do to get new one to work is to add it to settings and medalItems array
I have an array with lots of games that have unique id. I need to make a request for every id to retrieve minutes played for that specific game.
So my array looks something like this:
[
{
id: 1,
name: 'Team 1 vs Team 2'
},
{
id: 2,
name: 'Team 1 vs Team 2'
},
{
id: 3,
name: 'Team 1 vs Team 2'
},
{
id: 4,
name: 'Team 1 vs Team 2'
},
{
id: 5,
name: 'Team 1 vs Team 2'
}
]
I have been trying to forEach through the array, make a request with Axios to the API and then retrieve the data.
The Api looks like this. It is alot more, just narrowed it down. there is an image below with more description:
{
event: {
123123: {
id: 1,
elapsed: {
1: {
elapsed: '45'
}
}
}
}
The elapsed key is unique, for some reason, so I am using a Object.keys to "find" it.
My code:
array.forEach(game => {
axios.get(`http://example.com/${game.id}`)
.then(res => {
let time = 0;
Object.keys(res.data.event).map(eventId) => { //the eventId is the id for the event, in this case 123123.
Object.keys(res.data.event[eventId].elapsed).map(el => {
time = res.data.event[eventId].elapsed[el].elapsed; //el is the key-id for the elapsed object.
)};
)};
return time;
});
});
This does not work, I just get undefined. What am I doing wrong? And yes, the API looks like a mess. I have images below in case that will help you. It's a JSON file, I just have a JSON Formatter:
EDIT: Edited my code
In a wordpress plugin, there is a field box called 'data' where I can add code for it to pull, below in the code where it says 'data =' that is me referencing the box. In the box:
What I put in the field box entitled 'data':
{
contacts: [
{ name: "Name 1", email: "email1#test.com" },
{ name: "Name 2", email: "email2#test.com" }
]
};
This is what I put in the global field box, for it to apply to everything.
function (jQueryPopoverObj, mapObject, mapsvgInstance) {
// "this" = clicked mapObject
if(this.mapsvg_type == "region"){
return '<b>'+this.id+'</b>' +
this.data.contacts.map(function(contact) {
return contact.name + '<br>' +
'' + contact.email + ''
}).join('<br>');
} else if (this.mapsvg_type == "marker"){
return 'Marker - <b>'+this.id+'</b>, contact: '+this.data.email;
}
}
I want to also add { seat: "County Seat"} to the data portion and add it in the function.
I tried adding a line in the contacts, and then adding + '<br>' + contact.seat, after return contact.name, with no luck. Basically when it does the popover (which it pulls from global function for the template and the information from the data field box), I want it to have the CountySeat under the County Name (e.g. the County Seat for Harris County is Houston, so it would have Houston under Harris County).
Example of Lubbock County without the City name under it
var data = {
contacts: [
{ name: "Name 1", email: "email1#test.com" },
{ name: "Name 2", email: "email2#test.com" }
]
}
To add a new property seat you can simply do this-
data["seat"] = "County Seat"
or
data.seat = "County Seat"
JSFiddle
It looks like you want to set the seat assignment on the contact? You'd have to get the contact from the array, looping through each one and figuring out the one you want to use, then do contact.seat = "XYZ", which will add a seat property to the contact object. You can then use contact.seat in the string output but you have to null check it because it may be null. To help with that, I'd recommend defaulting it to an empty string like:
data = {
contacts: [
{ name: "Name 1", email: "email1#test.com", seat: "" },
{ name: "Name 2", email: "email2#test.com", seat: "" }
]
}
And then change it when it is assigned.