This is the set up:
In App.js i have routes for each step. i have a main object in which im updating values as the steps progress using props.
Here is my object:
const [postData, setPostData2] = useState({
'meta': {
"originally_created": todaysDate,
"user_agent": navigator.userAgent,
"ip_address": ip,
"tcpa_compliant": true,
"tcpa_consent_text": "By clicking Get My Free Quote below, I am agreeing to receive text messages from InsurTech Groups and business partners. I provide my signature expressly consenting to recurring contact from InsurTech Groups or its business partners at the number I provided regarding products or services via live, automated or prerecorded telephone call, text message, or email. I understand that my telephone company may impose charges on me for these contacts, and I am not required to enter into this agreement as a condition of purchasing property, goods, or services. I understand that I can revoke this consent at any time. Terms & conditions & Privacy policy apply.",
"landing_page_url": ""
},
"contact": {
"first_name": "",
"last_name": "",
"email": "",
"phone": "",
"address": "",
"city": "",
"state": "",
"zip_code": "",
"ip_address": ip,
},
"data": {
"drivers": [
{
"first_name": "",
"last_name": "",
"birth_date": "",
"gender": "",
},
{
"first_name": "",
"last_name": "",
"birth_date": "",
"gender": "",
}
],
"vehicles": [{
"year": "",
"make": "",
"model": "",
},
{
"year": "",
"make": "",
"model": "",
}
],
"requested_policy": {
"coverage_type": "",
},
"current_policy": {
"insurance_company": "",
}
}
});
Here is some logic so i can update the object with props:
useEffect(() => {
const stringifiedData = sessionStorage.getItem('main-form-data')
if (stringifiedData) {
const jsonData = JSON.parse(stringifiedData);
setPostData(jsonData);
}
}, []);
useEffect(() => {
sessionStorage.setItem('main-form-data', JSON.stringify(postData));
}, [JSON.stringify(postData)]);
const setPostData = (obj) => {
console.log('in app state', obj);
setPostData2(obj)
}
const setPostDataForPage = (data) => {
setPostData({ ...postData, ...data });
}
and this is how im passing it into each route:
<Route
path="/car-year"
element={<CarYear setPostData={setPostDataForPage} />}
/>
<Route
path="/car-make"
element={<CarMake setPostData={setPostDataForPage} />}
/>
<Route
path="/car-model"
element={<CarModel setPostData={setPostDataForPage} />}
/>
So here is the issue:
As i updated Car Year, Car Make & Car Model it updates in the console log as it supposed to but everytime it console log it completely overwrites the prior object.
Example:
YEAR STEP:
....rest of console log from object
vehicels: year: 1991
MAKE STEP:
....rest of console log from object
vehicels: make: Honda
as you can see it just over writes the year and replaces it with just the make
Here is how im updating in each step:
CAR YEAR PROPS UPDATE:
props.setPostData({
vehicles:
{
year: year,
}
})
CAR MAKE PROPS UPDATE:
props.setPostData({
vehicles: [
{
make: make,
}
]
})
Why does it do this and how can i fix it?
Here is a *bonus question lol, if i have two vehicles how can i make sure that when the person enters a second vehicle it doenst overwrite the first vehicle data!
I know this one is super long and thank you in advance!!!! <3
You're spreading the original state in the setter. React won't mutate the state synchronously, so you end calling all 3 setters on the original state.
To use the actual state, pass a callback to the state setter with the previous state as the parameter.
const setPostDataForPage = (data) => {
setPostData(prevData => { ...prevData, ...data });
}
Related
I am working in a pagination method where I want to load more data based on category type. Currently I am getting an Error:
endBefore: Starting point was already set (by another call to endAt, endBefore or equalTo).
I know I can't use endBefore and equalTo but I can't find a way to get what I want. If there is any approach to solve this will be amazing. Here is what I have of code.
function getPost() {
const vibesQuery = query(
vibesRef,
orderByChild("category"),
equalTo(categoryType),
limitToLast(2)
);
onValue(vibesQuery, (snapshot) => {
const data = snapshot.val();
if (data) {
const vibesArray = Object.values(data);
setVibes(vibesArray.reverse());
setLastVibe(vibesArray[vibesArray.length - 1][sortingType]);
}
});
function getMorePosts() {
const vibesQuery = query(
vibesRef,
orderByChild("category"),
equalTo(categoryType),
endBefore(lastVibe),
limitToLast(2)
);
onValue(vibesQuery, (snapshot) => {
const data = snapshot.val();
if (data) {
const vibesArray = Object.values(data);
setVibes([...vibes, ...vibesArray.reverse()]);
setLastVibe(vibesArray[vibesArray.length - 1][sortingType]);
}
setIsMoreLoading(false);
});
}
My data structure is:
{
"-LbzPjzin65Rt3ZIK1Lo": {
"caption": "Great",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1573942298.999069,
"fullname": "Bryant",
},
"-LbzPjzin65Rt3ZIK1Io": {
"caption": "Amazing",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1576382057.7584639,
"fullname": "Bravo",
},
"-LbzPjzin65Rt3ZIK1Ao": {
"caption": "Beatiful",
"category": "OUTDOORS", <-- THIS IS MY (categoryType)
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1586638159.889124, <-- THIS IS MY (lastVibe)
"fullname": "Bravo",
},
"-LbzPjzin65Rt3ZIK1Bo": {
"caption": "Fantastic",
"category": "OUTDOORS",
"cityVibe": "Chino",
"stateVibe": "CA",
"creationDate": 1604361787.34916,
"fullname": "Bravo",
},
}
If there is any additional information, let me know and thank you so much!
There is no way to pass multiple property values to filter on. What you can do in this case, it use Firebase's startAt/endBefore overload that takes two parameters. The first value is the property value you want to start/end at, but the second parameter is the key of the node you want to start/end at in case there are multiple matches on the first value.
So if you have the key of the last vibe in a variable called lastVibeKey, you can do:
query(
vibesRef,
orderByChild("category"),
endBefore(categoryType, lastVibeKey),
limitToLast(2)
);
I have a problem where I have example document in mongo atlas database:
{
"_id": {
"$oid": "5e517a946364cc48f0ccf1e7"
},
"firstName": "checkout1",
"lastName": "",
"companyName": "",
"phoneNumber": null,
"email": "exampleemail#gmail.com",
"country": "",
"adress": "",
"postcode": "",
"userId": "5daf414818d091616a0d917e",
"orderedItems": [{
"_id": "5e03b2072e0c98b9fa62388c",
"id": 3,
"title": "Blue shoes",
"img1": "product4/1.jpg",
"img2": "product4/2.jpg",
"cost": 70,
"color": "blue",
"quantity": 5
}],
"createdAt": {
"$date": "2020-02-22T19:01:40.228Z"
},
"updatedAt": {
"$date": "2020-02-22T19:01:40.228Z"
},
"__v": 0
}
I want to send a message with confirmation about purchased items and their quantity as shown below:
...
const {
...
email,
orderedItems
} = req.body;
var user = await User.findOne({ email: email });
let newCheckout = await Checkout.create({
...
email,
...
orderedItems,
userId: user._id
});
const htmlEmail = `
<div>Title of first ordered item: ${newCheckout.orderedItems[0].title}</div>
`;
const mailOptions = {
from: process.env.MY_TEST_EMAIL_ADRESS,
to: process.env.MY_EMAIL_ADRESS,
subject: 'new message',
replyTo: process.env.MY_EMAIL_ADRESS,
text: process.env.MY_TEST_EMAIL_ADRESS,
html: htmlEmail
};
transporter.sendMail(mailOptions, (err, info) => {});
...
I need this part of code:
const htmlEmail = `
<div>Title of first ordered item: ${newCheckout.orderedItems[0].title}</div>
`;
To map it similar to like in React where I can map the orderedItems array to div elements so in the end, the outcome message would look something like this (user would get all ordered item titles, and the number of div elements would depend on length of array):
<div>Item: ${newCheckout.orderedItems[0].title}</div>
<div>Item: ${newCheckout.orderedItems[1].title}</div>
<div>Item: ${newCheckout.orderedItems[2].title}</div>
My main question would be is it possible to do without template engines such as Jade, Pug, Mustache?
Template engines are not a requirement, just iterate by orderedItems:
const htmlMail = newCheckout.orderedItems.map(i => `<div>Item: ${i.title}</div>`).join('')
Yes.
orderedItems.map(item => `<div>Item: ${item.title}</div>`).join()
When you find yourself coming back to StackOverflow to ask about the next step in building your own custom rendering engine, take a minute to look at Knockout.
It will save you time in the long run, because you are going to want to make more and more customisations, and soon you have spent more time making a hack than you would have making it with a renderer.
Knockout is easy and you send a JSON object and it gets rendered on the client, and you can make customisations to the layout easily and quickly. You'll love it.
I am able to query a MongoDB Stitch database, but I get different results.
If I console log all my data, it appears like this (note the 'id: Uint8Array(12) [ 94, 67, 83, … ]'
item.find().asArray()
.then(data => {
console.log("Found docs", data)
});
However if I query it as an array:
// Find database documents
item.find({})
.toArray()
.then(xyz =>
this.setState({xyz})
)
Here is the data I receive, and state:
{
"xyz": [
{
"_id": {
"id": "DataView(12)",
"get_inc": "",
"getInc": "",
"generate": "",
"generationTime": 1581470496,
"inspect": "toString"
},
"company": "AAA",
"url": "http://www.google.com",
"loc": "sac, ca",
"gender": "female",
"tags": "clothes"
},
"{_id: {…}, company: \"BBB\", gender: \"male\", loc: \"sf…}",
"{_id: {…}, company: \"ZZZ\", gender: \"male\", loc: \"oa…}"
]
}
I would like to grab the objectID (which should be something like "5e435320e45ce24954381c52") which appears to be a unique key of a "bsonType": "objectId" schema, and I assume I need it converted as a string (?), so I can map it and have it serve as a unique key for use later in a table ("Each child in a list should have a unique "key" prop.").
Thanks!
Already is an ObjectId.
To get the string value just use toString()
item.find().toArray()
.then(data => {
console.log(data.map(elem => elem._id.toString()));
});
Trying get JSON array from json-server using observables and then giving the value to frontend and perform search on the JSON array received through observable
created a service and used HTTP get to connect to server and subscribed to it
created for loop to get value from returned value of subscription
**service.ts**
export class FormdtService {
baseul='http://localhost:3000/objects'//jsonserver url
constructor(private http:HttpClient) { }
getdt():Observable<any>{
return this.http.get(this.baseul)
}
}
**component.ts**
export class FormsComponent implements OnInit {
constructor(public fbu:FormBuilder,private fdts:FormdtService) {}
//creates the reactive form
form=this.fbu.group({
un:'',
id:''
})
// baseul='http://localhost:3000/objects/';
//ngsubmit control of form brings this function
ser(){
this.fdts.getdt().subscribe(dt=>{
console.log("data: "+dt[0])
this.formdt.push(dt)
//console.log("formdt :"+this.formdt[0])
for (let ite in this.formdt){
let ite1=JSON.parse(ite)
// console.log("ite :"+this.formdt[ite]);
//console.log("ite1"+ite1);
this.idlist.push(ite1.person.bioguideid.value)
if(ite1.person.bioguideid.stringify==this.idsearch)
this.objson=ite1
}});
}
idsearch:string
formdt:string[]
idlist:string[]
objson:JSON
ngOnInit() {
}
//this function is attached to button in frontend
ser(){
this.fdts.getdt().subscribe(dt=>
this.formdt.push(dt)//subscribes to service
for (let ite in this.formdt){
let ite1=JSON.parse(ite)
this.idlist.push(ite1.person.bioguideid.value)
if(ite1.person.bioguideid.value==this.idsearch)
this.objson=ite1
})}
**json**
[
{
"caucus": null,
"congress_numbers": [
114,
115,
116
],
"current": true,
"description": "Senior Senator for Tennessee",
"district": null,
"enddate": "2021-01-03",
"extra": {
"address": "455 Dirksen Senate Office Building Washington DC 20510",
"contact_form": "http://www.alexander.senate.gov/public/index.cfm?p=Email",
"fax": "202-228-3398",
"office": "455 Dirksen Senate Office Building",
"rss_url": "http://www.alexander.senate.gov/public/?a=rss.feed"
},
"leadership_title": null,
"party": "Republican",
"person": {
"bioguideid": "A000360",
"birthday": "1940-07-03",
"cspanid": 5,
"firstname": "Lamar",
"gender": "male",
"gender_label": "Male",
"lastname": "Alexander",
"link": "https://www.govtrack.us/congress/members/lamar_alexander/300002",
"middlename": "",
"name": "Sen. Lamar Alexander [R-TN]",
"namemod": "",
"nickname": "",
"osid": "N00009888",
"pvsid": "15691",
"sortname": "Alexander, Lamar (Sen.) [R-TN]",
"twitterid": "SenAlexander",
"youtubeid": "lamaralexander"
},
"phone": "202-224-4944",
"role_type": "senator",
"role_type_label": "Senator",
"senator_class": "class2",
"senator_class_label": "Class 2",
"senator_rank": "senior",
"senator_rank_label": "Senior",
"startdate": "2015-01-06",
"state": "TN",
"title": "Sen.",
"title_long": "Senator",
"website": "https://www.alexander.senate.gov/public"
},//end of single json array object
{
"caucus": null,
"congress_numbers": [
114,
115,
116
],
"current": true,
"description": "Senior Senator for Maine",
"district": null,....same repetition of structure
The ser function should give whole JSON array present in server to formdt[] and then iterate over it and get every object and convert to JSON and push bioguide to id array,search id from input and match with JSON nested value of each object in the array
nothing happens gives error in console :
_this.formdt is undefined at line 37 (this.fdts.getdt().subscribe(dt=>this.formdt.push=dt))
Given error is pretty explicit : this.formdt is undefined.
You've declared preperty type but haven't initialize it.
So replace formdt:string[] with formdt:string[] = []
I have an object like:
export const contact = {
_id: "1",
first:"John",
name: {
first:"John",
last:"Doe"
},
phone:"555",
email:"john#gmail.com"
};
I am reading it like
return (
<div>
<h1>List of Contact</h1>
<h1>{this.props.contact._id}</h1>
</div>
)
in this scenario I am getting expected output.
return (
<div>
<h1>List of Contact</h1>
<h1>{this.props.contact.name.first}</h1>
</div>
)
But when I read the nested property I am getting error like
Uncaught TypeError: Cannot read property 'first' of undefined
How to read these king of nested objects in react? Here is my source
Three things you need to address here:
this is your contacts-data and i don't see any first property within the name object:
export const contacts = {
"name": "mkyong",
"age": 30,
"address": {
"streetAddress": "88 8nd Street",
"city": "New York"
},
"phoneNumber": [{
"type": "home",
"number": "111 111-1111"
}, {
"type": "fax",
"number": "222 222-2222"
}]
};
You are calling this.props.fetchContacts(); on componentDidMount, hence in the first render call the state is still empty, the action call and the reducer will pass new props or change the state then you get to the second render call and that's the moment you have the data ready for use.
So you should check for the existing of the data before you try to use it. one way is to just conditionally render it (of course there are better ways to do it, this is just to make a point):
render() {
const { contacts } = this.props;
return (
<div>
<h1>List of Contacts</h1>
<h2>{contacts && contacts.name && contacts.name.first
//still getting error. "this.props.contacts.name" alone works
}</h2>
<h2>{contacts && contacts.address && contacts.address.city}</h2>
</div>
)
}
You are trying to use this.props.contact.name.first is that a typo? shouldnt it be contacts instead of contact?
EDIT:
As a followup for your comment, as a general rule in JavaScript (or any other language for that manner) you should always check the existence reference of an object before you are trying to access it's properties.
As for your use case you can use defaultProps if you must have a value to render or you can even simplify the scheme of your data.
This is much simpler to manage:
export const contacts =
{
"fName": "mkyong",
"lName": "lasty",
"age": 30,
"streetAddress": "88 8nd Street",
"city": "New York",
"homeNumber": "111 111-1111",
"faxNumber": "222 222-2222"
};
Than this:
export const contacts =
{"name": "mkyong",
"age": 30,
"address": {
"streetAddress": "88 8nd Street",
"city": "New York"
},
"phoneNumber": [
{
"type": "home",
"number": "111 111-1111"
},
{
"type": "fax",
"number": "222 222-2222"
}
]
};