So basically I have some promise, forEach, just a lot of issues with this single problem I need to solve. So the variables I work with has below structure:
persons = [object, object, object]
where each object has { user:number , username: string, latitude:number, longitude:number}
from there I try to figure out if my user/username is inside of one of these objects, if not found id like it to be created, if found found id like it to update their location. Sounds simple, I think the problem has blown out of proportion but nothing works. The code I have now does not work, its either I can never figure out when the user is not there, or I can not figure out how to get to stop creating me every time it find a user who is not me.
var getswamp = function(item, index) {
return new Promise(function(resolve, reject){
var result = false;
if (item.user === user && item.username === username) {
if ((item.latitude !== latitudenew) || (item.longitude !== longitudenew)) {
var id = item.id;
swampdragon.update('locationcurrent', {
user: user,
latitude: latitudenew,
longititude: longitudenew,
username: username,
id: id
}, function (context, data) {
console.log("data updated", data);
result = true;
resolve(result);
}, function (context, data) {
console.log("You may not be updated");
});
} else {
console.log("No location change");
result = true;
}
}else{
if ( item.index === person.index){
console.log(person);
resolve(result)
}
}
});
};
person.forEach(function (item, index) {
var swamping = getswamp(item, index);
swamping.then(function (result) {
console.log(result);
if (result === true) {
console.log("We have you");
} else if (result === false && (index === person.length - 1)) {
console.log('Index: ' + index + ' Length of list is ' + person.length);
swampdragon.create('locationcurrent', {
user: user,
latitude: latitudenew,
longititude: longitudenew,
username: username
}, function (context, data) {
console.log("data created", data);
}, function (context, data) {
console.log("You may not be created")
});
}
})
});
Any help/ideas would just be great.
The Promise is used when some asynchronous event happened.
Since I can not create such event, I made a static code as below:
var persons = new Array();
persons.indexOf = function(person) {
var index = -1;
this.forEach(function(obj, i) {
if (person.username == obj.username) {
index = i;
}
});
return index;
}
persons.addOrUpdate = function(person) {
var index = this.indexOf(person);
if (index == -1) {
person.user = this.length + 1;
this.push(person);
}
else { // update case
var obj = this[index];
obj.latitude = person.latitude;
obj.longitude = person.longitude;
}
}
persons.print = function() {
var str = "";
this.forEach(function(obj) {
str += obj.user + ". " + obj.username + " at location (" +
obj.latitude + ":" + obj.longitude + ")\n";
});
return str;
}
persons.addOrUpdate({username:'Adam', latitude:-0.0045, longitude:14.2015});
persons.addOrUpdate({username:'Eve', latitude:-0.0045, longitude:14.2015});
persons.addOrUpdate({username:'Abel', latitude:-0.0045, longitude:14.2015});
// Updating Able location
var person = {username:'Abel', latitude:10.1145, longitude:14.1234};
persons.addOrUpdate(person);
alert(persons.print());
Related
I am trying to parse pdf datas asynchronously, then populate a JS object with the content of the pdf file, and then return it in a Promise.
I am using the "pdfreader" module and its method parseFileItems()
async function parsePdfDatas(filePath){
var output = {};
var reader = new pdfreader.PdfReader();
await reader.parseFileItems(filePath, function(err, item) {
// item treatment populating output Object
});
return output;
}
parsePdfDatas("./****.pdf").then( function(output) {
console.log(output);
});
The await statement doesn't work, anybody get an idea ?
EDIT
After xMayank answer, i tried as follows, which doesn't work neither:
const fs = require('fs');
var pdfreader = require("pdfreader");
var row = {
id: "",
muban: "",
get mID() {
this.id.slice(6,8);
},
tambon: "",
get tID() {
this.id.slice(4,6);
},
amphoe: "",
get aID() {
this.id.slice(2,4);
},
changwat: "",
get cID() {
this.id.slice(0,2);
}
}
function parsePdfDatas(filePath){
return new Promise(function(resolve, reject){
var output = {};
var reader = new pdfreader.PdfReader();
reader.parseFileItems(filePath, function(err, item) {
if(item && item.text && item.text.match(/^-{1,3}[0-9]{1,4}-{1,3}$/) === null && item.y != 2.887){
if(item.x === 2.388){
// If the row object contains a muban entry, we push it at the end of output
if(row.id !== ""){
//console.log(row);
output[row.id] = {mName : row.muban, tName : row.tambon, aName : row.amphoe, cName : row.changwat};
}
// new line, row object reinitialization
row.id = row.muban = row.tambon = row.amphoe = row.changwat = "";
}
// correction for ่ ้
if(item.R[0].T === "%E0%B8%BD") item.text = "่";
if(item.R[0].T === "%E0%B8%BE") item.text = "้";
if(item.x >= 2.388 && item.x < 11.303)
row.id += item.text;
else if(item.x >= 11.303 && item.x < 17.969)
row.muban += item.text;
else if(item.x >= 17.969 && item.x < 23.782)
row.tambon += item.text;
else if(item.x >= 23.782 && item.x < 29.698)
row.amphoe += item.text;
else if(item.x >= 29.698)
row.changwat += item.text;
console.log(item.R[0].T + " -> " + item.text);
//console.log(item.text + " : x = " + item.x + " | y = " + item.y);
}
});
resolve(output);
});
}
parsePdfDatas("./files/mubans0.pdf").then((output) => {
console.log(output);
});
Works fine.
const { PdfReader } = require("pdfreader");
function readFile(file){
return new Promise(function(resolve, reject){
new PdfReader().parseFileItems(file, function(err, item) {
if (err) reject(err);
else if (!item) resolve();
else if (item.text) resolve(item.text);
});
})
}
readFile("./****.pdf")
.then(result =>{
console.log("Here", result)
})
So, a quick overview, this function is part of a larger app that ingests JSON data and prepares it to be rendered by Handlebars, which is then used for generating a PDF. This particular function has been giving me grief, as from my understanding of how async/await works, the data should be returned by the return returnArray at the bottom of the function. This however does not happen, and instead the empty array is returned. Could anyone offer insight as to why this is? (N.B. I've checked the data is present in iarr when it gets pushed, it's as though the return statement gets fired before the for loop has started.)
async function getPackageItem(item) {
try {
let returnArray = []
if (fs.existsSync(__dirname + "/../json/" + item.sku + ".json")) {
var file = fs.readFileSync(__dirname + "/../json/" + item.sku + ".json")
} else {
var file = fs.readFileSync(__dirname + "/../json/box.json")
}
const tb = JSON.parse(file);
for (var a = 0; a < item.quantity; a++) {
let iarr = [];
if (tb) {
tb.forEach(function(entry) {
ShopifyAuth.get('/admin/products/' + entry.product_id + '.json', (err, productData) => {
if (!err) {
ShopifyAuth.get('/admin/products/' + entry.product_id + '/metafields.json', (err, metafieldData) => {
if (!err) {
var itemObject = {};
var metaCounter = 0;
metafieldData.metafields.forEach(function(metadata) {
switch(metadata.key) {
case "notes": {
itemObject.wm_notes = metadata.value;
metaCounter++
break;
}
case "title": {
itemObject.title = metadata.value;
metaCounter++
break;
}
case "vintage": {
itemObject.year = metadata.value;
metaCounter++;
break;
}
case "shelfid": {
itemObject.shelf_id = metadata.value;
metaCounter++;
break;
}
case "bottleprice": {
itemObject.bottle_price = metadata.value;
metaCounter++;
break;
}
default: {
metaCounter++;
break;
}
}
if(metaCounter === metafieldData.metafields.length) {
itemObject.vendor = productData.product.vendor;
if (itemObject.title == undefined) {
itemObject.title = productData.product.title
}
if (itemObject.wm_notes == undefined) {
itemObject.wm_notes = " "
}
if (itemObject.year == undefined) {
itemObject.year = "Unspecified"
}
if (itemObject.shelf_id == undefined) {
itemObject.shelf_id = "N/A"
}
if (productData.product.images[1] == undefined) {
if (productData.product.images[0]) {
itemObject.logo = productData.product.images[0].src;
} else {
itemObject.logo = '';
};
} else {
itemObject.logo = productData.product.images[1].src;
}
itemObject.quantity = item.quantity;
iarr.push(itemObject)
if(iarr.length == tb.length) {
returnArray.push(iarr);
}
}
});
} else {
throw Error('Error retrieving product metadata');
}
})
} else {
throw Error('Error retrieving product data');
}
})
})
} else {
throw Error('Error loading JSON for specified box');
}
}
return returnArray;
} catch (e) {
console.log(e)
}
}
Edit: That's what I get for writing code at 3am, not sure how I missed that. Thanks for your feedback.
You marked your function async but you're not using await anywhere inside of it so you're not getting any of the benefits of using async. It doesn't make your function magically synchronous, you still have to manage asynchronicity carefully.
If ShopifyAuth.get supports returning a promise then await on the result instead of passing callbacks and your code will work, otherwise construct a Promise, do the async stuff in the promise, and return the promise from the function.
async function getPackageItem(item) {
let result = new Promise((resolve, reject) => {
// all your ShopifyAuth stuff here
if (err) {
reject(err);
}
resolve(returnArray);
});
return result;
}
I am creating a react native application.
I have a back button that fires the function findItem. findItem the uses async method searchJson. searchJson searches recursive json to find parent object based on id. However it never returns any results.
findItem:
findItem() {
//Pass null so top level json will be pulled
let result = this.searchJson(null).done();
let abv = 2;
// this.setState(previousState => {
// return {
// data: result,
// parentID: result.parentid
// };
// });
}
searchJson:
async searchJson(object) {
return new Promise(resolve => {
//use object or pull from porp - all data
let theObject = object == null ? this.props.data : object;
var result = null;
if (theObject instanceof Array) {
for (var i = 0; i < theObject.length; i++) {
result = this.searchJson(theObject[i]);
if (result) {
break;
}
}
}
else {
for (var prop in theObject) {
console.log(prop + ': ' + theObject[prop]);
if (prop == 'id') {
if (theObject[prop] == this.state.parentID) {
return theObject;
}
}
if (theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = this.searchJson(theObject[prop]);
if (result) {
break;
}
}
}
}
if(result != null)
resolve(result);
});
}
Any help will be greatly appreciated.
Ok so I never got this to work but my workaround was this.
I Modified the findItem method:
findItem() {
let FinNode = null;
for (var node in this.props.data) {
FinNode = this.searchJson(this.state.parentID, this.props.data, this.props.data[node].book);
if (FinNode != null) {
this.setState(previousState => {
return {
data: FinNode[0].book.parentid == "" ? null : FinNode,
parentID: FinNode[0].book.parentid
};
});
break;
}
}
}
And then the searchJson:
searchJson(id, parentArray, currentNode) {
if (id == currentNode.id) {
return parentArray;
} else {
var result;
for (var index in currentNode.books) {
var node = currentNode.books[index].book;
if (node.id == id)
return currentNode.books;
this.searchJson(id, currentNode.books, node);
}
return null;
}
}
This allowed for all my nodes to be searched and the for loop made so that there is no need for async. This does have some drawbacks but seems to work decently without any massive performance issues.
I am trying to push array content in a global defined empty array & then retrieve its contents inside another function.
Below is the code which i tried:
describe('My Test', function() {
var arrayf3=[];
var indexf3='not found';
it('Test starts', function() {
browser.ignoreSynchronization = true;
browser.get('https://www.w3schools.com/angular/');
var elm = element(by.id('leftmenuinner')).all(By.css('[target="_top"]'));
elm.count().then(function(count) {
Methods.pushToArray(0, count, elm);
})
var texttocheck='Data Binding';
Methods.getIndex(0, arrayf3.length, arrayf3, texttocheck);
console.log('Text content of global array is ' + arrayf3);
console.log('index of the array number having texttofind is ' + indexf3);
})
var Methods = {
getIndex :function (i, max, array, texttocheck) {
if (i < max) {
console.log('text[' + i + '].indexOf = ' + array[i].indexOf(texttocheck))
if (array[i].indexOf(texttocheck) > 0) {
indexf3 = i;
} else {
Methods.getIndex(i + 1, max, array, texttocheck);
}
}
},
pushToArray :function (i, max, elm) {
if (i < max) {
elm.get(i).getText().then(function(tmpText) {
console.log("The array "+tmpText);
arrayf3.push(tmpText);
})
Methods.pushToArray(i + 1, max, elm);
}
},
}
});
Problem is i am getting null values for below placeholder values:
Text content of global array is
index of the array number having texttofind is
I want the array value copied in this global empty array to be used & displayed in the same it block function 'Test starts'
Protractor's element.all inherently knows how to getText() on each of the elements and return the values as an array.
it('Test starts', function() {
browser.ignoreSynchronization = true;
browser.get('https://www.w3schools.com/angular/');
var getIndexOfElementByPartialText = function(inputText) {
return element(by.id('leftmenuinner')).all(by.css('[target="_top"]')).getText().then(function(values) {
var indexNumber;
values.forEach(function(value, index) {
if (new RegExp(inputText).test(value)) {
if (indexNumber === undefined) {
indexNumber = index;
} else {
throw new Error('multiple elements match the input text');
}
}
});
if (indexNumber === undefined) {
throw new Error('no elements match the input text');
} else {
return indexNumber;
}
});
});
expect(getIndexOfElementByPartialText('thing1').toBe(1);
expect(getIndexOfElementByPartialText('thing2').toBe(2);
});
Edited the answer to provide it in terms of a re-usable function.
I'm making a simple twitter app to work on my javascript.
The code below is supposed to identify every tweets location and count the number of tweets per location.
However, it doesn't increment, it just creates a new array.
What is wrong with my code? How can I make it better?
Thank you
var Twitter = require('node-twitter'),
twit = {},
loc = [];
twit.count = 0;
var twitterStreamClient = new Twitter.StreamClient(
//credentials
);
twitterStreamClient.on('close', function () {
console.log('Connection closed.');
});
twitterStreamClient.on('end', function () {
console.log('End of Line.');
});
twitterStreamClient.on('error', function (error) {
console.log('Error: ' + (error.code ? error.code + ' ' + error.message : error.message));
});
twitterStreamClient.on('tweet', function (tweet) {
if (loc.indexOf(tweet.user.location) === -1) {
loc.push({"location": tweet.user.location, "locCount": 1});
} else {
loc.loation.locCount = loc.loation.locCount + 1;
}
console.log(loc);
});
var search = twitterStreamClient.start(['snow']);
You need to rewrite on tweet callback:
var index = loc.reduce(function(acc, current, curIndex) {
return current.location == tweet.user.location ? curIndex : acc;
}, -1);
if (index === -1) {
loc.push({"location": tweet.user.location, "locCount": 1});
} else {
loc[index].locCount++;
}
Array.indexOf is not matching as you think it is. You're creating a new object and pushing it into the array, and regardless of whether its properties match a different object perfectly, it will not be === equal. Instead, you have to find it manually:
var foundLoc;
for (var i = 0; i < loc.length; i++) {
if (loc[i].location.x === location.x)
foundLoc = loc[i];
break;
}
}
if (!foundLoc) {
loc.push({location: location, count: 0});
} else {
foundLoc.count++
}