How to use if condition inside an object in react - reactjs

I'm trying to pass some data as payload to the api and I'm struggling to put condition inside of the object. I have an object called payload and I want to pass it in the api by checking the value of the state called profession.
const payload ={
name: registerData.fullname,
password: registerData.password,
confirm_password: registerData.confirmPassword,
email: registerData.email,
additional_info: {
profession == "Student" ? (
universityname: values.universityname,
course: values.course,
start_year: values.start_year,
end_year: values.end_year, ) :
(professorUniversity: values.professorUniversity,
department: values.department,
organizationName: values.organizationName,
organizationLocation: values.organizationLocation,
investorCompany: values.investorCompany,
investorCompanyWebsite: values.investorCompanyWebsite,
companyName: values.companyName,
govtSector: values.govtSector,
govtDesignation: values.govtDesignation,
)
},
};
// I'm passing the payload in the api.
api.post("some-url/register", payload);
as you can see in the top I want to pass the entire key and value if the condition is true. If the profession is not student I don't even pass the universityname key.

You should use a combination of ternary and spread operator
const payload ={
name: registerData.fullname,
password: registerData.password,
confirm_password: registerData.confirmPassword,
email: registerData.email,
additional_info: {
...(profession == "Student" ? {
universityname: values.universityname,
course: values.course,
start_year: values.start_year,
end_year: values.end_year, } :
{professorUniversity: values.professorUniversity,
department: values.department,
organizationName: values.organizationName,
organizationLocation: values.organizationLocation,
investorCompany: values.investorCompany,
investorCompanyWebsite: values.investorCompanyWebsite,
companyName: values.companyName,
govtSector: values.govtSector,
govtDesignation: values.govtDesignation,
})
},
};
I have explained something similar here
An example:
let car = "BMW";
const result = {
...(car === "BMW" ? {
make: "Germany"
} : {
make: "other"
})
};
console.log(result);

Related

setState an array and object

How do you setState an object and an array at the same time after passing id and data to a function? Because comment is not part of an array, I'm getting confused.
this.state = {
tasks: [
{ firstName: "boris", lastName: "Johnson", id: uuid() },
{ firstName: "Mary", lastName: "Whithaker", id: uuid() }
],
comment: "This is a comment message"
};
updateTask(id, task, comment, additional) {
const updatedProject = this.state.tasks.map(t => {
if (t.id === id) {
return {
...t,
firstName: task,
lastName: comment
};
}
return t;
});
this.setState({ tasks: updatedProject, comment: additional });
}
Your State is an object.
In that object there are two fields, tasks and comment.
Tasks is an array of objects, those objects have firstname, lastname and id fields.
Comment is a string.
When that code is doing setState at the end, it is creating a new object (see the {}), and then giving it the updatedProject array for tasks, and then the additional string for comment.
That whole object is then set. The array and string are values of fields in that object.

In React, how do I name a field of my form that is part of an array?

I'm building a React 16.13.0 application. In my form, I want to submit data (an address) as part of an array, so I set up my state like so ...
constructor(props) {
super(props);
this.state = {
countries: [],
provinces: [],
errors: [],
newCoop: {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
country: FormContainer.DEFAULT_COUNTRY,
}],
enabled: true,
email: '',
phone: '',
web_site: ''
},
I then created these functions for managing changes to the input fields ...
  handleInput(e) {
    let self=this
    let value = e.target.value;
    let name = e.target.name;
    this.setValue(self.state.newCoop,name,value)
  }
  setValue = (obj,is, value) => {
       if (typeof is == 'string')
         return this.setValue(obj,is.split('.'), value);
       else if (is.length === 1 && value!==undefined) { 
         return this.setState({obj: obj[is[0]] = value});
       } else if (is.length === 0)
         return obj;
       else
         return this.setValue(obj[is[0]],is.slice(1), value);
  }
...
                <Input inputType={'text'}
                   title= {'Street'} 
                   name= {'addresses[0].formatted'}
                   value={this.state.newCoop.addresses[0].formatted} 
                   placeholder = {'Enter address street'}
                   handleChange = {this.handleInput}
                   errors = {this.state.errors} 
                  /> {/* Address street of the cooperative */}
The Input.jsx file looks like the below ...
const Input = (props) => {
    return (  
  <div className="form-group">
      <FormLabel>{props.title}</FormLabel>
      <FormControl
            isInvalid={props.errors && Boolean(props.errors[props.name])}
            type={props.type}
            id={props.name}
            name={props.name}
            value={props.value}
            placeholder={props.placeholder}
            onChange={props.handleChange}
          />
      {props.errors && props.errors[props.name] && (
          <FormControl.Feedback type="invalid">
                 {props.errors[props.name].map((error, index) => (
                     <div key={`field-error-${props.name}-${index}`} className="fieldError">{error}</div>
                 ))} 
          </FormControl.Feedback>
      )}
  </div>
    )
}
export default Input;
However, when I attempt to change the value, I get the below error. I'm not sure what else I need to be doing to name my component such that I can successfully change it's value. I would prefer not to change the data structure in my constructor, but I'm willing to if that's what it takes.
TypeError: Cannot set property 'formatted' of undefined
FormContainer.setValue
src/containers/FormContainer.jsx:127
124 | if (typeof is == 'string')
125 | return this.setValue(obj,is.split('.'), value);
126 | else if (is.length === 1 && value!==undefined) {
> 127 | return this.setState({obj: obj[is[0]] = value});
| ^
128 | } else if (is.length === 0)
129 | return obj;
130 | else
ISSUE:
Cannot set property 'formatted' of undefined
// Reason : because you can't access obj["addresses[0]"]["formatted"]
// Solution : it should look something like obj["addresses"][0]["formatted"]
Because you are splitting up string by ., so a result you are getting
[
"addresses[0]",
"formatted"
]
Now that you have successfully splitted up the string ,
You are trying to get object by name, specifically obj["addresses[0]"], But you can't access the object index like this,
It will give you undefined, so as a result, you are getting the above error. you can check that exact error by running below code snippet,
const obj = {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
}],
};
const names = "addresses[0].formatted".split(".")
console.log("obj['addresses[0]'] ===>" , obj[names[0]])
console.log("obj['addresses[0]']['formatted'] ===>" , obj[names[0]][names[1]])
SOLUTION :
So now question is if not obj["addresses[0]"] this then what, the solution is obj["addresses"]["0"],
So you have 2 options :
First : change this addresses[0].formatted to addresses.0.formatted
Second : you need to split the sting with .split(/[\[\].]+/)
I would prefer second option as this addresses[0].formatted looks real form name, and this is how it should look like, you can check that in below code snippet also.
const obj = {
name: '',
types: [],
addresses: [{
formatted: '',
locality: {
name: '',
postal_code: '',
state: ''
},
}],
};
const names = "addresses[0].formatted".split(/[\[\].]+/)
console.log("obj['addresses'] ==>" , obj[names[0]])
console.log("obj['addresses']['0'] ==>" , obj[names[0]][names[1]])
console.log("obj['addresses']['0']['formatted'] ==>" , obj[names[0]][names[1]][names[2]])
NOTE :
Now, once you solved the issue, real issue come up in the picture, obj: obj[is[0]] = value, here obj is object so this will throw error , and also your setValue function is limited to that functionality only, it should be generic
handleInput = e => {
let name = e.target.name;
let value = e.target.value;
const keys = name.split(/[\[\].]+/);
this.setState(this.updateValue(this.state, keys, value));
};
// I've created a recursive function such that it will create a
// copy of nested object so that it won't mutate state directly
// obj : your state
// name : input name
// value : value that you want to update
updateValue = (obj, name, value, index = 0) => {
if (name.length - 1 > index) {
const isArray = Array.isArray(obj[name[index]]);
obj[name[index]] = this.updateValue(
isArray ? [...obj[name[index]]] : { ...obj[name[index]] },
name,
value,
index + 1
);
} else {
obj = { ...obj, [name[index]]: value };
}
return obj;
};
WORKING DEMO :
Your code is quite confusing, that's part of your problem to begin with, the other problem with your code is that it is not good practice to have nested objects in react's state. You can learn more by reading this answer in this other question.
Here is an example of what you could do with your code to set the state, however, notice that this is a bad way of solving the issue:
handleInput(e) {
let value = e.target.value;
this.setState(prevState =>{
...prevState,
newCoop: {
...prevState.newCoop
addresses: [
{
...prevState.newCoop[0].addresses
formatted: value
}
]
}
})
}

Graphql mutation query : how to access the data elements

const MUTATION_QUERY = gql`
mutation MUTATION_QUERY(
$name: bigint!
) {
insert_name(
objects: {
name: $name
}
) {
returning {
id
name
}
}
}
`;
const [onClick, { error, data }] = useMutation<{}, {}>(MUTATION_QUERY, {
variables: {
name: 1234,
},
});
My mutation query is inserting name in my table and autogenerating the id. On console logging the data variable I can view the fields id and name in the data object. But I am not able to access them them individually. How can I console.log "id". Thank you.
the console.log(data) looks like : {insert_name: {...}}
which expands to :
insert_name:
returning: Array(1)
0: {id: 1, name: 1234}
length: 1
_proto_: Array(0)
_typename: "insert_name_mutation_response
You can access the fields of an object with .
For example, if your object looks like this -
data = {
id: 1,
name: 'Jane',
}
You can get just the id with data.id
This works no matter how many layers deep your object may go, so take this example -
data = {
person: {
id: 1,
name: 'Jane',
}
}
You could get the id of person with data.person.id.
console.log(data.insert_name.returning[0].id) will give you the id returned.
For it to work in typescript we need to change the query to add the return type of data
const [onClick, { error, data }] = useMutation<{ReturnInsertNameProps}, {}>(MUTATION_QUERY, {
variables: {
name: 1234,
},
});
interface ReturnInsertNameProps {
insert_name: ReturnQueryProps;
}
interface ReturnProps {
returning: MessageProps[];
}
interface NameProps {
id: number;
name: number;
}
We can also use onCompleted method provided in useMutation if we want to process the result of the query.

How to send data to an api having multiple Nested Arrays in react

I have to send the modified data to an api which has json format as below:
{
"Customer": {
"name": "ABC",
"email": ABC#gmail.com,
"password": ""
},
"access": true,
"time": 2000
}
On save I want to set the respective state to api fields.
save=()=>{
let newCustomer={
access:this.state.access,
time:this.state.time,
name: //How can i set the state values for name,email and
password which is in nested form?
email:
password:
}
return axios.put('api',newCustomer)
.then(response => {
})
}
You can directly declare it like your json format.
let newCustomer={
access:this.state.access,
time:this.state.time,
Customer: {
name: ..., // state name from your nested form
email: ..., // state email from your nested form
password: ..., // state password from your nested form
},
}
save=(Customer)=>{
let newCustomer={
...Customer,
access: this.state.access,
time: this.state.time,
}
return axios.put('api', newCustomer)
.then(response => {
console.log(response);
})
}
Then newCustomer will be like Customer but access and time may be different.
In backend you cann access customer name and email like you are accessing an array

location object expected, location array not in correct format

I have spent doing such a straight forward thing. I just want to do a CRUD operation on a user model using nodejs, mongoose, restify stack. My mongo instance is on mongolab.
The user should contain a "loc" field . User schema is as follows :
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
var userSchema = new Schema( {
email_id : { type: String, unique: true },
password: { type: String},
first_name: String,
last_name: String,
age: String,
phone_number: String,
profile_picture: String,
loc: {
type: {},
coordinates: [Number]
}
});
userSchema.index({loc:'2d'});
var User = mongoose.model('user', userSchema);
module.exports = User;
the rest api used to post is as follows :
create_user : function (req, res, next) {
var coords = [];
coords[0] = req.query.longitude;
coords[1] = req.query.latitude;
var user = new User(
{
email_id : req.params.email_id,
password: req.params.password,
first_name: req.params.first_name,
last_name: req.params.last_name,
age: req.params.age,
phone_number: req.params.phone_number,
profile_picture: req.params.profile_picture,
loc: {
type:"Point",
coordinates: [1.0,2.0] // hardcoded just for demo
}
}
);
user.save(function(err){
if (err) {
res.send({'error' : err});
}
res.send(user);
});
return next();
},
Now when i do a POST call on curl -X POST http://localhost:3000/user --data "email_id=sdass#dfAadsfds&last_name=dass&age=28&phone_number=123456789&profile_picture=www.jakljf.com&longitude=1.0&latitude=2.0"
I get the following error
{
error: {
code: 16804
index: 0
errmsg: "insertDocument :: caused by :: 16804 location object expected, location array not in correct format"
op: {
email_id: "sdass#dfAadsfdsadkjhfasvadsS.com"
password: "sdass123DadakjhdfsfadfSF45"
first_name: "shaun"
last_name: "dass"
age: "28"
phone_number: "123456789"
profile_picture: "www.jakljf.com"
loc: {
coordinates: [2]
0: 1
1: 2
-
type: "Point"
}-
_id: "55efc95e0e4556191cd36e5e"
__v: 0
}-
}-
}
The location field is giving problems as the POST call works just fine if i remove the loc field from model
Below are the hits/trials I did :
1) Change userSchema.index({loc:'2d'}); to userSchema.index({loc:'2dsphere'});
2) Changing loc schema to everything given in Stackoverflow. I would like to know the right way to define this though.
3) Passing the hardcode 2d array but still it says Location object expected, location array not in correct format" what format is required for this ?
Any help in this regard is greatly appreciated. Thanks.
MongoDB 2d index requires the legacy coordinates pairs format, which is just an array of coordinates like [1, 2].
If you need GeoJSON support, please use the 2dsphere index.
userSchema.index({loc:'2dsphere'});
If you are using Spring Boot make sure you set the index type to 2DSphere:
#GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE) GeoJsonPoint location;

Resources