How create a new input field row by clicking a button reactjs - html

I am building an ecommerce app and I want to collect the users different phone numbers and address.
I want to create a new field where the user types new phone number and address
I tried using state to accomplish the task but I am geting error
TypeError: contactInfo.phoneInputs is undefined
const RegisterModal = ({openRegisterModal, setOpenRegisterModal}) => {
const [contactInfo, setContactInfo] = useState({
phoneInputValue : {},
phoneInputs: [],
addressInputValue : {},
addressInputs: [],
})
console.log(contactInfo)
const addContact = (e) => {
e.preventDefault()
const contactsphoneInfo = "phoneNumber";
const contactsAddressInfo = "address";
let phoneInputBox =
<Input name={contactsphoneInfo} star="false" label="PhoneNumber" type="text" className="col-md-6" />
let addressInputBox =
<Input name={contactsAddressInfo} star="false" label="address" type="text" className="col-md-6" />
setContactInfo(contactInfo.phoneInputs.push({phoneInputBox}))
console.log(contactInfo)
}
return (
<div>
{
contactInfo.phoneInputs.map(input => input)
}
button onClick={addContact}>Add</button>
</div>
)
}
export default RegisterModal
How do I fix this error
link to codesandbox
https://codesandbox.io/s/distracted-morse-s6zn0

your setstate is a bit fishy, I believe
setContactInfo({...contactInfo, phoneInputs: [...contactInfo.phoneInputs,phoneInputBox ]});
This should work . but i recommend you try for more clean code .
and console.log(contactInfo) before render if you check itll be undefined if you want to check the inital value still use useEffect then log it .

Related

Change the input initial value of controlled component in React

I have this input component
const FOO = props => {
const [inputValue, setInputValue] = useState(
props.editState ? props.initialValue : ""
);
const setSearchQuery = (value) => {
setInputValue(value);
props.onSearch(value);
};
return (
<input
placeholder="Select ..."
onChange={(e) => {
setSearchQuery(e.target.value);
}}
value={inputValue}
/>
)}
I'm using it like this
const BAR = props => {
const [fetchedData, setfetchedData] = useState({
value : "" // to get rid of can't change controlled component from undefined error
});
const params = useParams();
//request here to get fetchedData
return(
<FOO
onSearch={(value) => {
searchSomethingHandler(value);
}}
initialValue={
params.ID
? fetchedData.value
: ""
}
editState={params.ID ? true : false}
/>
)}
I need to set the initial value of the fetched data into the input so the user could see the old value and edit it, if I pass the data (fetchedData) as props it works perfectly,
but if I get the data through API it wont set the value cause it's empty at the first render,
how can I solve this please?
You'll probably want to make use of the useEffect hook to run code when a value updates.
In FOO:
const FOO = props => {
// ...
useEffect(() => {
// This hook runs when props.initialValue changes
setInputValue(props.initialValue);
}, [props.initialValue]);
// ...
};
You can leave BAR the same as before, I think. Though, I would put the request to the API inside a useEffect hook with an empty dependency array so you're not querying it on every render.

Mapping from JSON Get Request. Undefined

I am trying to connect to the USDA Food Central database using an API.
let uri = encodeURI(`https://api.nal.usda.gov/fdc/v1/foods/search?api_key=${MY_API_KEY}&query=${search}`)
I want to use the API to map certain fields.
class AddFoodItemList extends Component {
static contextType = AddFoodContext;
render() {
const listItems = this.context.FoodSearch.map((foods) =>
<FoodItem
key={foods.brandOwner}
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
);
return (
<div id="AddFoodItemList">
{listItems}
</div>
);
}
}
export default AddFoodItemList;
The returned JSON is this screenshot attached:
Returned JSON
I am getting an error, TypeError: Cannot read property 'map' of undefined.
Why do you think this is the case? Any sort of help or suggestions are appreciated!
You are attempting to access a property FoodSearch on the value of your AddFoodContext provider. The error tells you that this property is undefined. If the object in your screenshot is the value of your context then you want to access the property foods instead. This is an array whose elements are objects with properties brandOwner and fdcId.
On your first render this data might now be loaded yet, so you should default to an empty array if foods is undefined.
It's honestly been a long time since I've used contexts in class components the way that you are doing it. The style of code is very dated. How about using the useContext hook to access the value?
const AddFoodItemList = () => {
const contextValue = useContext(AddFoodContext);
console.log(contextValue);
const listItems = (contextValue.foods || []).map((foods) => (
<FoodItem
key={foods.fdcId} // brandOwner isn't unique
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
));
return <div id="AddFoodItemList">{listItems}</div>;
};
Here's a complete code to play with - Code Sandbox Link
const MY_API_KEY = "DEMO_KEY"; // can replace with your actual key
const getUri = (search) => `https://api.nal.usda.gov/fdc/v1/foods/search?api_key=${MY_API_KEY}&query=${encodeURIComponent(search)}`;
const AddFoodContext = createContext({});
const FoodItem = ({ brandOwner, fdcId }) => {
return (
<div>
<span>{fdcId}</span> - <span>{brandOwner}</span>
</div>
);
};
const AddFoodItemList = () => {
const contextValue = useContext(AddFoodContext);
console.log(contextValue);
const listItems = (contextValue.foods || []).map((foods) => (
<FoodItem
key={foods.fdcId} // brandOwner isn't unique
brandOwner={foods.brandOwner}
fdcId={foods.fdcId}
/>
));
return <div id="AddFoodItemList">{listItems}</div>;
};
export default () => {
const [data, setData] = useState({});
useEffect(() => {
fetch(getUri("cheese"))
.then((res) => res.json())
.then(setData)
.catch(console.error);
}, []);
return (
<AddFoodContext.Provider value={data}>
<AddFoodItemList />
</AddFoodContext.Provider>
);
};

Mapping JSON data with React Hooks

I'm working on a small project and I am trying to map data from a JSON file into my project.
In components with nested data, I keep getting an let data = props.data["runways"];.
data.json:
{
"runways":[
{
"slot":"Area 1",
"planes":[
{
"name":"PanAm",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
},
{
"name":"PanAm 222 ",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
}
]
}
]
}
App.js,
I pass the JSON data as props:
import planeData from './plane_info.json'
const Container = () => {
const [planeDataState, setPlaneDataState] = useState({})
const planeData = () => setPlaneDataState(planeData[0].runways)
return (
<>
<MyPlane planeInfo={planeDataState}/>
<button onClick={planeData} type="button">Get Data</button>
</>
)
}
and finally, I want to bring my data into my component:
MyPlane.jsx
const MyPlane = (props) => {
let data = props.data["runways"];
if(data)
console.log(data, 'aaa')
return (
<>
{
data ? (
<div>
<span>{props.planeInfo.name}</span>
<span>RAIL TYPE: {props.planeInfo.type}</span>
</div>
) : <h6>Empty</h6>
}
</>
);
}
According to the error message, the problem occurs at this line of code: let data = props.data["runways"]; However, I believe that I am passing the data for runways from the JSON file.
I've never worked with React Hooks to pass data, so I'm confused about why this error is occurring.
In order to map effectively over the JSON data it's necessary to understand how that data structure is composed.
If you're unsure, using JSON.stringify() is a great way to get the "bigger picture" and then decide what exactly is it that you want to display or pass down as props to other components.
It appears you wish to get the plane data (which is currently an array of 2 planes). If so, you could first get that array, set the state, then map over it to display relevant info. Perhaps like this:
const data = {
"runways":[
{
"slot":"Area 1",
"planes":[
{
"name":"PanAm",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
},
{
"name":"PanAm 222 ",
"number":"12345",
"start":{
"time":1585129140
},
"end":{
"time":1585130100
}
}
]
}
]
}
function App() {
const [ planeData, setPlaneData ] = React.useState(null)
React.useEffect(() => {
setPlaneData(data.runways[0].planes)
}, [])
return (
<div className="App">
{/* {JSON.stringify(planeData)} */}
{planeData && planeData.map(p => (
<p key={p.name}>
{p.name} | {p.number} | {p.start.time} | {p.end.time}
</p>
))}
</div>
)
}
ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Here const planeData = () => setPlaneDataState(planeData[0].runways)
In this line, planeData[0].runways will be undefined according to the json file which you have shared.
Instead try setting and passing entire json object, ie,
const planeData = () => setPlaneDataState(planeData)
Try this, And then inside MyPlane.jsx component, let data = props.data["runways"]; this won't be undefined. So , the error won't come.
At the beginning there is no data in props.data['runways'] (also you can use props.data.runways, I guess you come from another language like Python as of this syntax that you are using), because you sent the request at first, it takes time for request to be satisfied, so you need to check in your <MyPlane /> component to see if there is a runways key in data and then proceed to render the component, something like below:
const MyPlane = (props) => {
const data = props.data
return (
<>
{
data.runways
? <>
...your render able items that you wrote before
</>
: <p>There is no data yet!</p>
}
</>
)
}
Also please note that you might return something from component. At your case your render is inside the if(data){...} statement! what if the condition was not satisfied? which is your current error case !
NOTE: please check that you are passing your planeDataState as planeInfo prop to the child component, so you might have something like:
const data = props.planInfo
to be able to use the data variable that you've defined before the render part.

Angular Detect change on html input element or trigger it automatically

I want to get the value of an input element once it changes. The value is not typed by the user. I got it from a source and bind it with [(ngModel)] or just [value]. I have tried everything. But I still got nothing. I even search on how to trigger an event manually. if some of you can help me, I would be grateful
My code: I have tried various things. But this is the one that seems to work. But this instructions in the subscribe method was executed twice
this.maxGroup$ = this.reponseService.getMaxGroupe();
this.maxGroup$.subscribe((rep: MaxGroup) => {
if (rep) {
this.maxGroupe = rep;
this.max = rep.valeur;
this.questions.forEach(q => {
let r = new Reponse();
r.QuestionId = q.Id.toString();
r.Question = q;
r.Groupe = rep.valeur;
this.reponses.push(r);
});
}
this.max++;
this.maxGroupe.valeur = this.max;
let ref = this.reponseService.createMax(this.maxGroupe);
this.reponseService.deleteMax(this.idMax);
});
In my service:
return this.db.list('/maxGroup').snapshotChanges().map(snapshots => {
return snapshots.map(c => ({ key: c.payload.key, ...(c.payload.val()) as {} }));
});
In my template:
<div *ngFor="let m of maxGroup$ | async">
<input #KeyMax type="text" id="keyMax" [(ngModel)]="m.key" [value]="m.key" (change)="keyChange()"/>

Trying to use local-storage in react app, however not working in between pages

I'm trying to save an array to local-storage in my react app, so that if the user goes to another page in the app, or closes the app and reopens it, the value stays the same.
In my index.js (simplified code):
import ls from 'local-storage';
function HomeIndex() {
const [testString, setTestString] = useState(ls('localStorageText') || '');
if(condition){
const array = [1,2,3];
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
}
return (
<div className="col-12">
{testString}
</div>
);
}
When I press the button, and the condition is met, the testString value displays 123 as it should. And it holds the value. However it does not work when I try and add my own array.
const array = reversedHistoryText;
const saveArray = {key: array};
localStorage.setItem('key1', JSON.stringify(saveArray));
const restoreValue = localStorage.getItem('key1');
setTestString(JSON.parse(restoreValue).key);
It doesn't display anything the first time the button is clicked, then gives error on the 2nd time:
Error: Minified React error #31;
When I do this test:
setTestString(JSON.stringify(reversedHistoryText));
The result is []
You need to set your testString to the localStorage value.
import ls from "local-storage";
import React, { useEffect, useState } from "react";
function MyComponent() {
const [testArray, setTestArray] = useState([]);
useEffect(() => {
setTestArray(ls("testArray") || []);
}, []);
function handleClick(e) {
ls("testArray", [
{ id: 1, name: "this" },
{ id: 2, name: "thing" },
{ id: 3, name: "is" },
{ id: 4, name: "cool" }
]);
setTestArray(ls("testArray"));
}
return (
<div className="col-12">
<ul>
{testArray.map(obj => (
<p key={obj.id}>{obj.name}</p>
))}
</ul>
<button onClick={handleClick}>Set The State</button>
</div>
);
}
export default MyComponent;
You don't need to use third party for localStorage.
Just use localStorage without importing anything.
To save,
localStorage.setItem('key', 'value');
To get value from localStorage,
localStorage.getItem('key') // value
To remove value,
localStorage.removeItem('key')
Use
if(condition) ls('localStorageText', "TEST");
setTestString(ls('localStorageText')|| ' '); }
Instead
if(condition){ ls('localStorageText', "TEST");
setTestString(ls('localStorageText')); }
Because when you go back to the index page a new instance of this component is rendered and i think the condition in the if statement is false, so the code don't change the setstate value...
To set use
localStorage.setItem('itemName', JSON.stringify(arrayName));
To get use
whatEver = jQuery.parseJSON(localStorage.getItem('itemName'));
Local storage stores strings