I have developed an Angular4 appln that calls a nodeExpressJS server to fetch JSON data and also adds data to the JSON object. The following is the onSubmit function of the addemployeeform.
onSubmit(formValue: any) {
console.log("Form Value = " + JSON.stringify(formValue, null, 4));
let newEmployee: Emp;
let last: any;
this._employeeService.lastEmployeeID().subscribe((last: any) => last = last,
err => console.log(err));
newEmployee = {
//id: employeeCount + 1,
id: last + 1,
name: formValue.name,
manufacturer: formValue.manufacturer,
type: formValue.type,
batchno: formValue.batchno,
expdate: formValue.expdate,
price: formValue.price
};
// console.log(newEmployee.id );
let temp = this._employeeService.addEmployee(newEmployee).subscribe(err =>
console.log(err));
this.router.navigate(['employees']);
}
But then it isn't pushing the id property to the JSON for newEmployee.
{id: 1, name: "Paracetamol", manufacturer: "Ranbaxy", type: "Tablet", batchno …}
{id: 2, name: "Sinarest", manufacturer: "GSK", type: "Tablet", batchno: …}
{id: 3, name: "Viagra", manufacturer: "Pfizer", type: "Capsule", batchno: …}
{name: "Aspirine", manufacturer: "Aspirine", type: "Syrup", batchno: "03/46", expdate: "03/04/2023", …}
newEmployee is Aspirine.
And on uncommenting console.log(newEmployee.id ); line of code
I get a Nan error
First, shouldn't last be defined as a number and not any?
Second, and more importantly, the lastEmployeeId call is most likely asynchronous, meaning it will not have completed before the next line of code is complete. You need to add all of the code that executes after that operation within the subscribe.
this._employeeService.lastEmployeeID().subscribe(
(last: any) => {
last = last;
newEmployee = {
//id: employeeCount + 1,
id: last + 1,
name: formValue.name,
manufacturer: formValue.manufacturer,
type: formValue.type,
batchno: formValue.batchno,
expdate: formValue.expdate,
price: formValue.price
};
// console.log(newEmployee.id );
let temp = this._employeeService.addEmployee(newEmployee).subscribe(
employee => {
console.log(employee);
this.router.navigate(['employees']);
},
err => console.log(err)
);
And with that much code in the first function passed to your subscribe, you may want to instead make it it's own function:
this._employeeService.lastEmployeeID().subscribe(
(last: number) => this.processEmployeeId(last),
err => console.log(err));
processEmployeeId(last: number) {
// Your code here.
}
if last is supposed to be a number type then state so:
let last: number;
If you're going to use typescript - you might as well use it to your advantage.
Related
i want to do the following: get a random name with fetch from this website https://swapi.dev/api/people/, which i did and i can see it in my html page then i want also to get a random planet, here i need to access the homeworld key, and to return the link, before returning the link i formatted to get a random url and from this one i also have to show the name of the planet on my page. The first fetch works fine, at least i think but the 3rd .then() is not working or at least i don't know how to access the information from the homeworld url. This is my first time trying fetch() and it will be nice if you guys can help me telling where i did wrong in code and maybe different solutions but not so complicated :D tnks
let randomNumber = Math.floor(Math.random()*9)
const fetchPromise = fetch("https://swapi.dev/api/people/");
let test
let test2
let planets = document.querySelector('#age')
fetchPromise
.then((response) => {
if (!response.ok) {
throw new Error(`Http error: ${response.status}`);
}
return response.json();
})
.then((json) => {
console.log(json.results[randomNumber].name)
showRandomUserData(json)
test = json.results[0].homeworld
test = test.slice(0, -2)
// console.log(test + randomNumber + "/");
// console.log(test + "/" + randomNumber + "/");
test = test + randomNumber + "/";
return fetch(test)
// return fetch("https://swapi.dev/api/planets/2/");
})
.then(response => response.json()).then(json =>
{ test2=json.name
console.log(test2);
planets.innerHTML = test2
})
showRandomUserData = (randomUser) => {
document.querySelector("#name").innerHTML =
randomUser.results[randomNumber].name;
}
Solved
Here's a simple solution that uses fetch() to grab data from both those URLs and then insert all the people and the one planet that is returned into your web page:
function myFetch(...args) {
return fetch(...args).then(response => {
if (!response.ok) {
throw new Error(`fetch failed with status ${response.status}`);
}
return response.json();
});
}
Promise.all([
myFetch("https://swapi.dev/api/people/"),
myFetch("https://swapi.dev/api/planets/2/")
]).then(([people, planet]) => {
const peopleDiv = document.getElementById("people");
let peopleHTML = "";
for (let p of people.results) {
peopleHTML += `<div>${p.name}</div>`;
}
peopleDiv.innerHTML = peopleHTML;
const planetDiv = document.getElementById("planets");
let planetHTML = `<div>${planet.name}</div>`;
planetDiv.innerHTML = planetHTML;
}).catch(err => {
console.log(err);
});
<div id="people"></div>
<hr>
<div id="planets"></div>
As for using the results, the people URL returns a structure that looks like this:
{
count: 82,
next: 'https://swapi.dev/api/people/?page=2',
previous: null,
results: [
{
name: 'Luke Skywalker',
height: '172',
mass: '77',
hair_color: 'blond',
skin_color: 'fair',
eye_color: 'blue',
birth_year: '19BBY',
gender: 'male',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [],
vehicles: [Array],
starships: [Array],
created: '2014-12-09T13:50:51.644000Z',
edited: '2014-12-20T21:17:56.891000Z',
url: 'https://swapi.dev/api/people/1/'
},
{
name: 'C-3PO',
height: '167',
mass: '75',
hair_color: 'n/a',
skin_color: 'gold',
eye_color: 'yellow',
birth_year: '112BBY',
gender: 'n/a',
homeworld: 'https://swapi.dev/api/planets/1/',
films: [Array],
species: [Array],
vehicles: [],
starships: [],
created: '2014-12-10T15:10:51.357000Z',
edited: '2014-12-20T21:17:50.309000Z',
url: 'https://swapi.dev/api/people/2/'
}
}
So, you have people.results which is an array and you can access people.results[n] to get an item from that array. That item will be an object which has properties like .name, .height, etc...
The specific planet URL you show returns a single planet object like this:
{
name: 'Alderaan',
rotation_period: '24',
orbital_period: '364',
diameter: '12500',
climate: 'temperate',
gravity: '1 standard',
terrain: 'grasslands, mountains',
surface_water: '40',
population: '2000000000',
residents: [
'https://swapi.dev/api/people/5/',
'https://swapi.dev/api/people/68/',
'https://swapi.dev/api/people/81/'
],
films: [
'https://swapi.dev/api/films/1/',
'https://swapi.dev/api/films/6/'
],
created: '2014-12-10T11:35:48.479000Z',
edited: '2014-12-20T20:58:18.420000Z',
url: 'https://swapi.dev/api/planets/2/'
}
So, you access properties on that object as in planet.name.
Notice that the people results are paged. There are 82 total results, but only 10 come in this first result. The rest come with results for other pages such as https://swapi.dev/api/people/?page=2.
Similar to this answer but using async/await to avoid callback hell. If you can, try using this approach. Why?
Excellent recommendation in that answer by jfriend00 to use Promise.all instead of separate fetch calls, as that enables fetching to happen in parallel. To know more.
sandbox to test and try
const fetchData = async (...args) => {
try {
const response = await fetch(...args);
return response.json();
} catch (err) {
throw new Error(`fetch failed with status ${err?.message}`);
}
};
const updateDOM = (people, planet) => {
document.getElementById("people").innerHTML =
people.results.reduce((s, p) => s + `<div>${p.name}</div>`, "");
document.getElementById("planets").innerHTML = `<div>${planet.name}</div>`;
};
const populateData = async () => {
try {
const [people, planet] = await Promise.all([
fetchData("https://swapi.dev/api/people/"),
fetchData("https://swapi.dev/api/planets/2/"),
]);
// do stuff with 'people' or 'planet'
// example, get
// const firstPersonsHomeworld = people.results[0].homeworld;
// console.log(firstPersonsHomeworld);
// or
// const planetName = planet.name;
// console.log(planetName);
updateDOM(people, planet);
} catch (err) {
// errorHandler(err);
console.error(err);
}
};
// start app
populateData();
I am trying to filter out empty array but its not happening
I was trying to compare value which are present inside my database and fileName
I tried arr.filter(Boolean);
even i tried arr.filter((item)=>item)
PS: fileName is not an array value so I converted it into array.
function checkDoc(data, childProduct, fileName, pathName, req, res) {
return new Promise((resolve, reject) => {
Document.findAll({
raw: true,
where: {
product_id: childProduct.id,
},
})
.then((productDoc) => {
if (productDoc.length === 0) {
return resolve(addDocument(data, childProduct, fileName, pathName));
} else {
let fileArray = [];
fileArray.push(fileName);
productDoc.forEach((singleProduct) => {
let productValue = singleProduct.name;
let unMatchedValues = fileArray.filter((value) =>
productValue.includes(value)
);
let removedBoolean = unMatchedValues.filter((item) => item);
console.log("Document Name: ", removedBoolean);
});
}
})
.catch(function (err) {
return reject("Can't be added please try again :) " + err);
});
});
}
fileName:
ABC
PQR
XYZ
Installation and Configuration
Java
Node Js
where as in singleProduct.name it contain
[ABC]
[PQR]
[Installation and Configuration]
[XYZ]
attached Output Image :
Expected OutPut:
matchedValue:
[`document name: ABC`]
[`document name: PQR`]
[`document name: Installation and configuration`]
[`document name: XYZ`]
unmatchedValue:
['Java']
[`Node Js`]
If you're asking how to filter an array of objects to remove those with empty names, here's an example:
const team = [
{ name: 'max', age: 21 },
{ name: '', age: 19 },
{ name: 'james', age: 33 },
{ name: '', age: 30 },
];
// Log the entire team
console.log('Team:', team);
// Log only those team members with names
console.log('Team with names:', team.filter(x => x.name));
// Log only the names
console.log('Names:', team.filter(x => x.name).map(x => x.name));
I am not able to assign dynamic name to my array (I want to assign value of auth_ID as name of array).
Problem - it is saving auth_ID as text in db, whereas i want its value.
Here is my code:
exports.insert_totalcalllogs = functions.firestore
.document('calllogs/{calllogsId}')
.onCreate(
async (snapshot: { data: () => { (): any; new(): any; entryDate_show:any; authid: any; fullname:any; }; },context:any) => {
// todos details.
const text = snapshot.data();
const entryDate_show = text.entryDate_show;
const auth_ID = text.authid; // want this to be name of array
const fullname = text.fullname;
admin.firestore().collection("totalcalllogs").doc(entryDate_show).set({
auth_ID: [
{ number: 1, fullname: fullname , authid: auth_ID},
],
age: 12,
})
.then(function() {
console.log("Document successfully written!");
})
.catch(function(error: any) {
console.error("Error writing document: ", error);
});
...// some code
See image of console:
If you want to use a variable as the name of property in a JavaScript object, use the square bracket notation when building the object:
admin.firestore().collection("totalcalllogs").doc(entryDate_show).set({
[auth_ID]: [
{ number: 1, fullname: fullname , authid: auth_ID},
],
age: 12,
})
Note the square brackets around [auth_ID].
I want the user to be able to write a specific account number in the endpoint, been trying to validate the endpoint param if it exists in my database. I couldn't get it to work, please what am I doing wrong?
My validation
const validateReq: [
param('accountNumber').exists().custom(acctNo => accountNumberExist(acctNo)),]
My accountNumberExist function
accountNumberExist(inputAcct) {
const isfound = accounts.find(account => account.accountNumber === inputAcct);
if (isfound === undefined) throw new Error('Account Number not found');
}
My accounts file
const accounts = [
{
id: 1,
accountNumber: 1234567890,
createdOn: new Date(),
owner: 1,
type: 'current',
balance: 23444.43,
status: 'active',
},
{
id: 2,
accountNumber: 1234167890,
createdOn: new Date(),
owner: 1,
type: 'savings',
balance: 2233444.43,
status: 'active',
},
{
id: 3,
accountNumber: 9987654321,
createdOn: new Date(),
owner: 2,
type: 'saving',
balance: 73444.43,
status: 'active',
},
];
But this is always throwing the 'Account Number not found' error even though, the req.param exists in my accounts database.
Params are parsed as string by express middleware. Say I make a req to path defined below like /some/1000
app.get('/some/:path', (req, res, next) => {
console.log(typeof req.param.path)
// outputs string
})
So you need to parse the incoming parameter to integer (Number) since you've stored accountNumber as integer. So adding toInt to chain like below should solve it:
const validateReq: [
param('accountNumber').exists().toInt().custom(acctNo => accountNumberExist(acctNo)),
]
accountNumber inside accounts array is a number whereas req.params.accountNumber is a string. You need to convert the data type. You can do it as
accountNumberExist(inputAcct) {
const isfound = accounts.find(account => account.accountNumber.toString() === inputAcct);
if (isfound === undefined) throw new Error('Account Number not found');
}
I think that the problem is your query. find method runs in an asynchronous way, that's why isfound property does not contain the data you expect. Here is a simple approach using promises which works pretty well for me.
// Here is your function.
accountNumberExist(inputAcct) {
return accounts.find({accountNumber: inputAcct})
.then(result => {
if (result.length == 0) {
console.log("Account Number not found");
return Promise.reject('Account Number not found');
}
return Promise.resolve();
});
}
I have a problem in my express project that I can't resolve since a day. I can't push some data into array element. Let me demonstrate my code and data.
Here is my result data which coming from mongodb:
result = {
name: 'Workflow',
steps:[
{ name: 'First Step',
assignee: '2cb56eadab3fbdc46dcb896e2ec68f33'
},
{
name: 'Second Step',
assignee: '1h374jab3fbdc46wer896e2ec687as'
}
],
__v: 0
}
Here is my code block:
var save = function(data, next) {
return new Promise(function(resolve) {
if (_.isEmpty(data._id)) {
Workflow.create(data, function (err, result) {
if (err) return next(err);
result.steps.forEach(function(step) {
step.detail = {
fullName: 'blablabla',
avatar: 'blablabla'
}
});
resolve(result);
});
}
}
}
After running code block my expectation is:
result = {
name: 'Workflow',
steps:[
{ name: 'First Step',
assignee: '2cb56eadab3fbdc46dcb896e2ec68f33',
detail: {
fullname: 'blablabla',
avatar: 'blablabla'
}
},
{
name: 'Second Step',
assignee: '1h374jab3fbdc46wer896e2ec687as',
detail: {
fullname: 'blablabla',
avatar: 'blablabla'
}
}
],
__v: 0
}
I can't get my expectation from result data and can't understand why detail is not assign steps array elements?
You can't directly modify the objects that MongoDB gives you, they're frozen.
You can copy the object and assign to the copy:
const copy = {...result, steps: result.steps.map(step => {
const stepCopy = {...step};
stepCopy.detail =
fullName: 'blablabla',
avatar: 'blablabla'
};
return stepCopy;
})};
resolve(copy);
That can actually be written more concisely, but it starts getting hard to read:
const copy = {...result, steps: result.steps.map(step => (
{...step, detail: {
fullName: 'blablabla',
avatar: 'blablabla'
}}
)};
resolve(copy);
Or, since I notice you're using ES5 syntax (but presumably with polyfills):
var copy = Object.assign({}, result);
copy.steps = copy.steps.map(function(step) {
var stepCopy = Object.assing({}, step);
stepCopy.detail = {
fullName: 'blablabla',
avatar: 'blablabla'
};
return stepCopy
)};
resolve(copy);
You'll need a polyfill for Object.assign (or I see Underscore/Lodash in your code, you can use _.extend instead, you literally just replace Object.assign with _.extend in the above).
You can do it in another way. Add detail object in the model itself. Set default value in the model definition.