EDIT: I've added the res.send(json), wasn't included the snippet.
I'm trying to extract/scrape a website and combine their output into json data. However when I run the endpoint, the response combines every result into its key, instead of adding a record per iteration. To expound, I get:
{
item: "item1item2item3item4item5item6",
title: "title1title2title3title4title5title5",
price: "price1price2price3price4price5price6"
}
This is my target output format though..:
{ item: "item1",
title: "title1",
price: "price1",
itemlink: "itemlink1" },
{ item: "item2",
title: "title2",
price: "price2",
itemlink: "itemlink2" },
{ item: "item3",
title: "title3",
price: "price3",
itemlink: "itemlink3" }, etc...
Here's the below snippet:
request(url, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
var json = [];
/* Pulls out all the titles
$('.item-name').each(function() {
var title = $(this).text();
json2.push({title: title});
})
*/
function getID(str) {
return str.split('viewitem.php?iid=')[1];
}
$('.catlist').each(function(key, index) {
var title = $('.item-name').text();
var price = $('.catprice').text();
var id = getID($('h2').children().attr('href'));
var itemlink = $('h2').children().attr('href');
json.push({
id: id,
title: title,
price: price,
itemlink: itemlink
});
})
}
res.send(json)
})
I'm out of my wits, already spent hours on this. Any idea why they are not iterating properly for me? Thanks in advance!
$('.catlist').each(function(key, index) {
var title = $(this).find('.item-name').text();
var price = $(this).find('.catprice').text();
var id = getID($(this).find('h2').children().attr('href'));
var itemlink = $(this).find('h2').children().attr('href');
var temp =
{
id: id,
title: title,
price: price,
itemlink: itemlink
};
json.push(temp);
})
You need to find children for each .catlist and push them to array one by one
As you can see in your code you are assigning value to json in every iteration. So that's why it's not adding new record to it.
Have a look to this code
$('.catlist').each(function(key, index) {
var title = $('.item-name').text();
var price = $('.catprice').text();
var id = getID($('h2').children().attr('href'));
var itemlink = $('h2').children().attr('href');
var temp =
{
id: id,
title: title,
price: price,
itemlink: itemlink
};
json.push(temp);
})
Try this
json.push( {
id: id,
title: title,
price: price,
itemlink: itemlink
});
Related
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) {
I'm trying to get the id or name of the selected folder in a fuelux tree but couldnt manage to get it done.
My tree is a classic folder/file type tree and I want to be able to see the id of the folder when I click on a file.
this is my datasource for tree
var treeDataSource = new DataSourceTree({
data: [
{ name: 'Elektronik Belgelerim', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F1' } },
{ name: 'Gelen Kutusu', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F2' } },
{ name: 'Giden Kutusu', type: 'folder', 'icon-class': 'blue', additionalParameters: { id: 'F3' } },
{ name: 'Çöp Kutusu', type: 'folder','icon-class':'green', additionalParameters: { id: 'I1' } },
//{ name: 'Çöp Kutusu', type: 'item', 'icon-class': 'success', additionalParameters: { id: 'F4' } },
//{ name: 'Reports', type: 'item', additionalParameters: { id: 'I1' } },
//{ name: 'Finance', type: 'item', additionalParameters: { id: 'I2' } }
],
delay: 400
});
js function for tree begins like this inside tree-custom.js
var e = function (e, i) {
this.$element = t(e), this.options = t.extend({}, t.fn.tree.defaults, i), this.$element.on("click", ".tree-item", t.proxy(function (t) {
this.selectItem(t.currentTarget)
}, this)), this.$element.on("click", ".tree-folder-header", t.proxy(function (t) {
this.selectFolder(t.currentTarget)
}, this)), this.render()
};
and this is where I add the links under folders again inside trree-custom.js. Very primitive I know but that's all I can do with my current skillset. The part I added is between quotes. Rest came with beyondadmin theme and looks like usual fuelux.
selectFolder: function (e) {
//alert("testselectFolder");
//
//alert($('#myTree').tree({ dataSource: dataSource }));
var i, n, r, o = t(e),
s = o.parent(),
a = s.find(".tree-folder-content"),
l = a.eq(0);
//-----------------------------------------------
var li = $('<li>');
var TcgbLink = $('<a href=/E-Belge/Main/Folder/Inbox/?Type=1&DocumentTypeId=3>e-TCGB</div>' +"</br>");
var FaturaLink = $('<a href=/E-Belge/Main/Folder/Inbox/?Type=1&DocumentTypeId=4>e-Fatura</div>' + "</br>");
var Dolasim = $('<a href=>e-Dolasim Belgesi</div>');
li.append(FaturaLink);
a.append(li);
li.append(TcgbLink);
a.append(li);
li.append(Dolasim);
a.append(li);
//-----------------------------------------------
o.find(".fa.fa-folder").length ? (i = "opened", n = ".fa.fa-folder", r = "fa fa-folder-open", l.show(), a.children().length || this.populate(o)) : (i = "closed", n = ".fa.fa-folder-open", r = "fa fa-folder", l.hide(), this.options.cacheItems || l.empty()), s.find(n).eq(0).removeClass("fa fa-folder fa-folder-open").addClass(r), this.$element.trigger(i, o.data())
},
Now these links are being generated under all 4 folders. I want to be able to get the id (or name, preferably Id) of the folder so I can assign new Type parameters to querystring.
So far I tried to reach the id with this.data.id to no avail.
Instead of injecting the folder's children in the selectFolder callback, it is recommended to add the children via the dataSource callback (as in this example code: http://getfuelux.com/javascript.html#tree-usage-javascript).
The first argument to the dataSource is the "parent data" when you click on a tree node (with the second argument being the callback that you send the new array of child data).
This way you can use the selected event for getting your ID, because it gets the jQuery data passed to it.
I need to create an array like this:
events: [
id :'1',
title: 'All Day Event'
},{
id : '2',
title: 'some name'
},{
id: 999,
title: 'some title',
}]
I am executing this code inside a loop:
$events['title'] = 'hello';
$events['id'] = '1';
It's returning:
[ title: "hello", id: "1" ]
[ title: "hello", id: "1" ]
How can I change the code to meet my requirement?
Try:
var id1 = '1';
var title1 = 'All Day Event';
var events = [];
events.push({
id :id1,
title: title1
});
for a loop:
titles = ['All Day Event1','All Day Event2'];
ids = ['1','2'];//note both array need to have the same length
$.each(titles,function(i,v){
events.push({
id :ids[i],
title: titles[i]//or v
});
})
See some examples here and read some more about JSON
You need to iterate the JSON while adding dimensions and values in it
I'm having some problems to filter with 03 select boxes, country, state and city.
How can I get select boxes nested?
And How can I get some filter with these data?
My code in script.js using MySQL Database:
var serviceFilterCountry = "http://localhost:8000/filtercountry";
var serviceFilterProvince = "http://localhost:8000/filterprovince";
var serviceFilterCity = "http://localhost:8000/filtercity";
$scope.countries = new DevExpress.data.DataSource(serviceFilterCountry);
$scope.provinces = new DevExpress.data.DataSource(serviceFilterProvince);
$scope.cities = new DevExpress.data.DataSource(serviceFilterCity);
//var dataSourceCity = new DevExpress.data.DataSource(serviceFilterCity);
//var dataSourceF = new DevExpress.data.DataSource(serviceFilter);
$scope.selectedProvince = null;
$scope.filterProvincesByCountry = function(e) {
var countryP = e.value;
$scope.provinces.filter("country", countryP);
$scope.provinces.load().done(function(result) {
$scope.selectedProvince = result.state;
});
};
$scope.selectedCity = null;
$scope.filterCitiesByProvince = function(e) {
var provinceC = e.value;
$scope.cities.filter("country", $scope.countries.select('country'));
$scope.cities.filter("state", provinceC);
$scope.cities.load().done(function(result) {
$scope.selectedCity = result.city;
});
};
To filter data by a selectbox value you can use the onValueChanged event. For example, the following code shows how to filter cities by country id:
JS:
$scope.countries = new DevExpress.data.DataSource({
store: [{id: 1, text: "USA"}, {id: 2, text: "Canada"}]
});
$scope.cities = new DevExpress.data.DataSource({
store: [{id: 1, countryId: 1, text: "NY"}, {id: 2, countryId: 2, text: "Toronto"}]
});
$scope.filterCitiesByCountry = function(e) {
var countryId = e.value;
$scope.cities.filter("countryId", countryId);
$scope.cities.load();
};
HTML:
<div dx-select-box="{dataSource: countries, displayExpr: 'text', valueExpr: 'id', onValueChanged: filterCitiesByCountry}"></div>
<div dx-select-box="{dataSource: cities, displayExpr: 'text', valueExpr: 'id', bindingOptions: { value: 'selectedCity' } }"></div>
More information about the filter operation you can find here.
I've create a small sample that demonstrates this approach in action - http://plnkr.co/edit/SR93AIRSp9TUuA5fYmpa
I'm new to JS and coding in general so I'm not sure how to effectively write a function for this. I want to write a function that takes an object as an argument and returns another object.
OrderFormContents = {
servicesSelected: {
hdrPhotos: "selected",
panos: "selected",
twilightPhotos: "selected"
}
}
hdrPhotos, panos, and twilightPhotos are all SKUs / unique identifiers.
I want to return an object like like:
CompletedOrderFormContents = {
servicesSelected: {
hdrPhotos: {
sku: "hdrPhotos",
calculatedPrice: 100, // returned from an object stored as a Session variable called calculatedPrices
title: "HDR Photography" //returned from looking up the sku from a Services collection.
},
panos: {
sku: "panos",
calculatedPrice: 125,
title: "Panoramas"
},
twilightPhotos: {
sku: "twilightPhotos",
calculatedPrice: 200,
title: "Twilight Photography"
}
}
}
So far I have been brute forcing it, explicitely defining all of the skus, and it is dumb:
var myFunction = function(OrderFormContents) {
CompletedOrderFormContents = {
servicesSelected: ""
};
CompletedOrderFormContents.servicesSelected.hdrPhotos = {
sku: "hdrPhotos",
calculatedPrice: Session.get("calculatedPrices").hdrPhotos,
title: Services.find({"sku" : "hdrPhotos"}).fetch()[0].title
};
CompletedOrderFormContents.servicesSelected.panos = {
sku: "panos",
calculatedPrice: Session.get("calculatedPrices").panos,
title: Services.find({"sku" : "panos"}).fetch()[0].title
};
CompletedOrderFormContents.servicesSelected.twilightPhotos = {
sku: "twilightPhotos",
calculatedPrice: Session.get("calculatedPrices").twilightPhotos,
title: Services.find({"sku" : "twilightPhotos"}).fetch()[0].title
};
};
How would I refactor this code so I'm at least not explicitly defining the SKU for each statement and explicitly defining each statement for each SKU? I've got UnderscoreJS installed.
EDIT Got it working.
completedOrderFormContents = {
servicesSelected: {}
};
for (sku in OrderFormContents.servicesSelected) {
if (OrderFormContents.servicesSelected.hasOwnProperty(sku)) {
completedOrderFormContents.servicesSelected[sku] = {
sku: sku,
price: Session.get("calculatedPrices")[sku],
title: Services.find( { "sku" : sku }).fetch()[0].title
}
}
}
I got it working.
//servicesSelected does not currently exist in completedOrderFormContents,
//so gotta create it - ie. simply doing completedOrderFormContents = {} would not work
//because the for loop is going to try and assign something to .servicesSelected
//later on and it needs that .servicesSelected key to already be there
completedOrderFormContents = {
servicesSelected: {}
};
for (sku in OrderFormContents.servicesSelected) {
if (OrderFormContents.servicesSelected.hasOwnProperty(sku)) {
completedOrderFormContents.servicesSelected[sku] = {
sku: sku,
price: Session.get("calculatedPrices")[sku],
title: Services.find( { "sku" : sku }).fetch()[0].title
}
}
}