How to save draft of a long form in ReactJS - reactjs

I have a long form with over 80 input fields. After submission, it works fine and saves data in a neo4j database. I need to have 'Save Draft' function in case the users want to fill the form later. How can I implement it ?
Edit:
I am trying to save the form data (including empty input fields) into the neo4j database.
I have an array and the form in the constructor:
constructor(props){
super(props);
this.state = {
mydata: {
data1: {},
data2: {},
}
};
this.saveAsDraft = this.saveAsDraft.bind(this);
<form>
<MyInput
title="Name"
inputs={[{title: "name", inputType: "text" }]}
onChange={this.handleChange}
type="freeText"
/>
<MyInput
title="Email"
inputs={[{title: "email", inputType: "text" }]}
onChange={this.handleChange}
type="freeText"
/>
</form>
}
And I used following method to handle the form submission:
async saveAsDraft(){
const name = this.state.mydata['data1']['name'];
const email = this.state.mydata['data1']['email'];
const neo4j = require('neo4j-driver')
const driver = neo4j.driver('bolt://localhost:7687', neo4j.auth.basic('neo4j', 'pass'))
const session = driver.session({database: 'neo4j'})
const txc = session.beginTransaction()
try {
const result = await txc.run(
'CREATE (:Person { name: $name, email: $email })',
{
name: name,
email: email
}
)
await txc.commit()
console.log('commited')
} catch (error) {
console.log(error)
await txc.rollback()
console.log('rolled back')
} finally {
await session.close()
}
}
It works when the input fields are filled. But it shows following error when input fields are empty:
Neo4jError: Expected parameter(s): name, email
how can i handle the empty input fields here ? I want to execute the cypher queries and create nodes and relations with empty input values.
I also need to extract the data later to populate them to the form when the user wants to continue editing the form later.

If it's required to access the form answers from different devices or browsers, then you'll have to store the data into database.
If it's enough, that the users can access the saved form data only on same browser, you can use local storage to achieve that. Some state management libraries like redux and mobxstate tree offer persist feature, so you can persist the whole state of your app in the local storage with minor config.

Related

Placeholder disappear after user interact with inputs

I'm facing this issue in my react app:
The application is used for manage storage of a shop, there is one page in which user can add a new obj ( with name , quantity etc.) and there is a page used for UPDATE the obj.
In the "update" page I display the same form of the "new" page but with the current value as placeholder, so that the user can see what value is actually set and change just one or few of the values and leave the others as they are.
The problem is that when the user interact with the input ( like start typing then cancel ) the placeholder disappear and the value is updated as empty.
Now I would like that if user leaves the field empty after interacting with it, the placeholder should appear again, and I would like to make that if the input is left empty then it would not be updated or should be updated with the previous value.
I'm using antd library, so all inputs and stuff are taken from there.
const [data, setData]=useState({
numero: 0,
date: '' ,
nome: "",
...
//get current data
useEffect(() =>get(child(dbRef,'test/' + searchParams.get('id'))).then((snapshot)=>{
if(snapshot.exists()){
setData(snapshot.val())
console.log('[CONVERTED-DATA]',snapshot.val(), '[stato]', data);
}else{
console.log('[GET] NO data available')
}
}).catch((error)=>{
console.log(error)
})
, [])
//now "data" is populated with the values from db
function onChange(e) {
const value = e.target.value ;
setData({
...data,
[e.target.name]: value
});
console.log("[CHANGE-VALUE]", value);
console.log("[event]", e);
}
<Form>
<Form.Item
name="nome"
label="Nome"
rules={[ { type: "string", min: 3 }]}
initialValue={data.nome}
>
<Input
placeholder={data.nome}
value={data.nome}
name="nome"
onChange={onChange}
className="update-input"
/>
</Form.Item>
... more inputs

How do i use the value of Ngmodel in a seperate file to display the value?

I am new to Angular and TypeScript. I have defined input field phone number and collected its value in text box. Now i want that value to be displayed when sending email to the admin. I tried the below code but its not working.
its throwing error while continous intgeration
Declaration of instance field not allowed after declaration of instance method. Instead, this should come at the beginning of the class/interface
Here is the code
<div class="text-input">
<label i18n="##phoneNumberTitle" for="phoneNumber">i18n</label>
<input
id="phoneNumber"
autocomplete="off"
placeholder="##placeholderphoneNumberTitle"
i18n-placeholder="##placeholderphoneNumberTitle"
name="phoneNumber"
#phoneNumber="ngModel"
[(ngModel)] = "phone_number"
required
/>
this is the typescript code
/**
* Call service to send notification via email to admin
*/
phone_number:any;
sendEmailToNotificateAdmin(user) {
const data = {
to: environment.adminEmail,
cc: '123vron#gmail.com',
subject: 'A new user has registered',
body: `
A new user has registered at XYB.
Phone Number: ${this.phone_number}
};
}
The correct way is by using template strings with backtick like this:
const age = 2;
const message = `I am ${age} years old`.
In your code, you are using parenthesis, change it to curly brackets.
Somewhere in your .ts component file you should have a variable called phone_number in order to capture the input.
#Component({...})
export class YourComponent implements OnInit {
phone_number: string;
constructor() {}
public ngOnInit(): void {}
sendEmailToNotificateAdmin(user) {
const data = {
to: environment.adminEmail,
cc: '123vron#gmail.com',
subject: 'A new user has registered',
body: `
A new user has registered at XYB.
Phone Number: ${this.phone_number}
};
}
}

Why do I have to push enter twice in this react input form?

I'm new to react and have made a basic weather app. When it initialises, it automatically uses location coordinates to populate the fields. However, I also have included an input form, allowing the user to type in a different city if they choose to do so.
I store the users search term in state. If a search term has been inputted, I would like the app to make an API call based on that term, otherwise just use the coordinates provided.
//state to hold search term
const [manualSearch, setManualSearch] = useState({
searchTerm: ""
})
// function to retrieve weather data from weather api based on coordinates or search term
function getWeather() {
let currentWeatherRequest = ""
//if there is a search term
if (manualSearch.searchTerm !== "") {
currentWeatherRequest = `http://api.openweathermap.org/data/2.5/weather?q=${manualSearch.searchTerm}&appid=${API_KEY}&units=metric`
} else {
// api based on coordinates
currentWeatherRequest = `http://api.openweathermap.org/data/2.5/weather?lat=${coords.latitude}&lon=${coords.longitude}&appid=${API_KEY}&units=metric`;
}
fetch(currentWeatherRequest)
....etc
Here is the function to update state and refresh the search if a user inputs a town to search and presses enter
// search for town manually
function handleManualSearch(event) {
if (event.which === 13) {
setManualSearch({
searchTerm: event.target.value
})
getWeather()
}
}
I pass this function to a component which contains the input field via props. Here is the code for the input#
<input id="testingthis" placeholder="Enter a new location e.g. London" name="city" type="text" onKeyPress={(event) => props.manualSearch(event)} />
This all works, but only when I press enter twice. I figured it would have something to do with the fact that setState is asynchronous, so I tried adding the getWeather function as a callback like so:
// search for town manually
function handleManualSearch(event) {
if (event.which === 13) {
setManualSearch({
searchTerm: event.target.value
}, () => { getWeather()})
}
}
...but have the same issue with this. What am I missing? I'm fairly new to react so brief explanation would be helpful also.
thanks!

Mongoose: Not able to add one item in Mongoose array SchemaType. Although more than one could be added

Below is my Schema
var makerSchema = new mongoose.Schema({
materials:[
{
type: String,
required:[true, "Material is a required field"],
trim:true,
lowercase:true,
enum:{
values:['wood','metal','plastic','glass','concrete','other'],
message: 'Please choose from the given options only!'
}
}
]
},{
timestamps:true
})
var Maker = mongoose.model('Maker', makerSchema);
Below is my route
router.post('/maker', async (req, res) => {
try {
var maker = new Maker(req.body);
await maker.save();
res.status(200).send();
} catch (error) {
if (error.name === "ValidationError") {
let errors = {};
Object.keys(error.errors).forEach((key) => {
errors[key] = error.errors[key].message;
});
return res.status(400).send(errors);
}
res.status(500).send(error);
}
})
Below is my form in which I can select multiple items by holding Ctrl and clicking options.
<form action="/maker" method="POST">
<select multiple class="form-control" id="materials" name="materials">
<option>Wood</option>
<option>Metal</option>
<option>Glass</option>
</select>
<input type="submit" value="Submit">
</form>
But in case I select single option I get the following error, although works fine for multiplele options:
{"materials.0":"Please choose from the given options only!"}
How do I resolve this error and allow users to choose not only multiple but single options too?
My guess is that when selecting ONE material only you will get the "wrong" datatype for maker.materials, a String.
When selecting multiple materials you will receive a Array<String> in your router.
So I would check the datatype of materialsin the router before saving the Maker. And convert it to Array if it is not one already.

ReactJS: Update a specific Object from an array of Objects in the state

So, I have a a state of users which gets filled up with an array of Objects from the backend. Say, I want to update the details of a specific User Object from that array and then update the current state with the updated details. How do I go about doing that?
What I currently do is force a refetch from the server once the update request is successful to update the state again but I was wondering if there's a better way to do it without refetching from the server again.
For example, on the code below. I wanted to update PersonTwo's age.
state = {
users: [
{
name: PersonOne,
age: 1
},
{
name: PersonTwo,
age: 1
}
]
}
Let's say you have id field in your object. You can use map function to return new array and save it to your state.
updateUser(userId){
const updatedUsers = this.state.users.map( (user) => {
if(userId !== user.id) {
return user;
}
return {
...user,
//write some updated info here, for example:
age: 40
}
}):
this.setState({
users: updatedUsers
});
});
The best way is to do as you are doing right now that first send the values to the server and then fetch the latest data from the database because if you update the view before successful update on the server you might end up showing which does not exist actually. There is a possibility that your server did not accept that change but somehow you updated the view on user request. It is not a good thing, but if you still want to do that follow the steps below:
step-1: check the array index on which the update of user data is done and then
const newArray = Array.from(this.state.oldArray);
newArray[i] = 'test';
step-2: assign this new array to the old one:
this.setState({oldArray: newArray})
You can use functional setState as a success callback of POST/PUT call.
this.setState(prevState => {
users: ... // operation using prevState.users
})

Resources