setState on empty field in JSON object - javascript

I have the empty field ModifiedBy. I need to populate it with a username stored in session storage, userInfo.name.
const [details, setDetails] = useState("");
const handleCreateData = (e) => {
setDetails((prev) => {
return { ...prev, ModifiedBy: userInfo.name };
});
}
This method only works when ModifiedBy is already populated in data. I need to be able to populate ModifiedBy when it is empty, and update it is populated.
A quick example of my JSON
{
"ModifiedBy": "Ciaran Crowley"
}

const handleCreateData = (e) => {
setDetails((prev) => {
prev.ModifiedBy = userInfo.name || ''
return prev;
});
}

Related

Can't add object to existing array (useState react native)

I have addText() that runs on click event
const [list, setList] = useState([])
const [value, setValue] = useState("")
useEffect(() => {
getObjectItem("tasks")
.then(t => setList(t.item))
.catch(e => { console.log(e) })
}), []
// A function that add data to the list array
function addText(text) {
console.log(list);
if (value !== "") {
setList(prev =>
[...prev,
{ text: text, isSelected: false }] // Adding a JS Object
)
setObjectItem("tasks", list);
setValue("")
} else {
alert("Please type in something!")
}
}
Output from console.log(list):
Array [
Object {
"isSelected": true,
"text": "Test",
}
]
getObjectItem("tasks") function:
const getObjectItem = async (name) => {
try {
const jsonItem = await AsyncStorage.getItem(name)
const item = JSON.parse(jsonItem)
return {
status: 'success',
name: name,
item: item
}
} catch (err) {
return {
status: 'error',
name: name,
error: err
}
}
}
Why can't I add values to the existing list array with setList() in addText() function?
Setting state is asynchronous.
In addText you write:
setObjectItem("task", list)
which will set the value in AsyncStorage to whatever list was, not what it will be after the state has been updated. The easiest solution is to create the new array then set it to state and AsyncStorage.
Try to put
.then(t => setList([t.item]))
instead of what you wrote

The object empty check is not working and changing the logic

So I am doing a form validation check and I have taken 'formErrors' and set the errors in this object. However it is initially {} and in my code I am checking for Object.keys(formErrors).length===0 which returns true for even {}
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const url = '/collectdetails';
const handleSubmit = (e) => {
e.preventDefault();
setFormErrors(validate(formValues));
// setIsSubmit(true);
console.log(noErrors);
if (noErrors) {
const { fullName, phoneNumber, emailAddress, role, lookingFor, company } =
formValues;
const data = {
Name: fullName,
MobileNumber: phoneNumber,
Email: emailAddress,
Role: role,
LookingFor: lookingFor,
CompanyName: company,
};
getDetails(url, data).then((user) => {
const { Response } = user;
if (Response === 'OK') {
setCurrentUser(phoneNumber);
navigate('/');
}
});
}
};
useEffect(() => {
if (Object.keys(formErrors).length === 0) {
console.log(formErrors);
setNoErrors(true);
}
}, [formErrors]);
So When I submit the handleSubmit() method is run and it has 2 nested checks. The first one is for noErrors which is a bool state that checks if my object is empty. I have console logged it and it returns true when the component loads as the object is {} in the beginning. Is there any way for me to put a check so that I can see if there are some keys present in the object?
useEffect will run every time your formErrors object changes. This includes the first render.
It would probably be better for you to put your useEffect logic inside your submit handler. The formErrors state object just seems to function as a temporary store for you as you immediately call setNoErrors(true) if it is populated:
const [formValues, setFormValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const url = '/collectdetails';
const handleSubmit = (e) => {
e.preventDefault();
// just store in a normal variable
const errors = validate(formValues);
// setIsSubmit(true);
console.log(noErrors); // this isn't defined in your code
// just check the errors object for keys
if (Object.keys(errors).length === 0) {
// errors object is empty
console.log(errors);
setNoErrors(true);
const { fullName, phoneNumber, emailAddress, role, lookingFor, company }
= formValues;
const data = {
Name: fullName,
MobileNumber: phoneNumber,
Email: emailAddress,
Role: role,
LookingFor: lookingFor,
CompanyName: company,
};
getDetails(url, data).then((user) => {
const { Response } = user;
if (Response === 'OK') {
setCurrentUser(phoneNumber);
navigate('/');
}
});
}
};

How to setup default value of fetched data

I am fetching data from my "backend" CMS - everything works fine, but when I want to setup default value I am getting error of undefined data.
My content is divided into some categories e.g.
const [category1, setCategory1] = useState([]);
const [category2, setCategory2] = useState([]);
Then I am fetching data from backend
useEffect(() => {
const fetchData = async () => {
const result = await client.query(
Prismic.Predicates.at('document.type', 'post'),
{ pageSize: 100 }
);
if (result) {
const category1Arr = [];
const category2Arr = [];
result.results.forEach((post) => {
switch (post.data.category[0].text) {
case 'Category1':
category1Arr.push(post);
break;
case 'Category2':
category2Arr.push(post);
break;
default:
console.warn('Missing blog post category.');
}
});
setCategory1(category1Arr);
setCategory2(category2Arr);
return setDocData(result);
} else {
console.warn(
'Not found'
);
}
};
fetchData();
}, []);
Code above works without any issues, BUT chosen category should have one post opened by default.
I am having menu when you can pick category and therefore I am using activeComponent function.
const [activeComponent, setActiveComponent] = useState('category1');
const modifyActiveComponent = React.useCallback(
(newActiveComponent) => {
setActiveComponent(newActiveComponent);
},
[setActiveComponent]
);
So category1 is active on default, therefore the category should also have default post.
This is what I tried:
const [postTitle, setPostTitle] = useState('');
const [postText, setPostText] = useState([]);
{activeComponent === 'category1' &&
category1.length > 0 && category1.map((post) => {
return ( <button onClick={()=> {setPostTitle(post.data.title[0].text); setPostText(post.data.body)}}
And data are shown typical just as a {postTitle} & {postText}
I tried to put default value in each category like this
useEffect(() => {
if (activeComponent === 'category1') {
setPostTitle(category1[2].data.title[0].text);
setPostText(category1[2].data.body);
}
if (activeComponent === 'category2') {
// same here just with category2 }
}, [activeComponent, category1, category2]);
But the code above gives me an error or undefined data even though it should be correct.
How can I achieve to make a default value with this logic above? Everything works like charm, just the default data does not work :(
This is array of objects:
In your last piece of code you have a typo, here:
useEffect(() => {
if (activeComponent === 'category1') {
setPostTitle(category1[2].data.title[0].text);
setPostText(category[2].data.body);
}
if (activeComponent === 'category2') {
// same here just with category2 }
}, [activeComponent, category1, category2]);
it should be:
useEffect(() => {
if (activeComponent === 'category1') {
setPostTitle(category1[2].data.title[0].text);
setPostText(category1[2].data.body);
}
if (activeComponent === 'category2') {
// same here just with category2 }
}, [activeComponent, category1, category2]);
in the first if statement, in second setPostText, you have category instead of category1.

How to check input for "Enter" key press

I'm working on a slightly complicated component that basically allows a user to type into an input, and then trigger a search (external API) for that product, the current issue however is that using the "Enter" key press, causes different behaviour and I want to sync up the behaviour of the "Find" button and "Enter". But before that I'm having some trouble on establishing where that check should happen, here's my React component:
export type CcceHook = {
allowForClassification: boolean,
classifyInProgress: boolean,
dataProfileId: string,
embedID: string,
handleCancelClassify: () => void,
handleClassify: (event?: SyntheticEvent<any>) => void,
handleCloseModal: () => void,
handleShowModal: () => void,
isDebugMode: boolean,
resultCode: string | null,
shouldShowModal: boolean,
};
// returns Ccce input fields based on the object form model - used in context provider
const getCcceValues = (object?: FormObjectModel | null) => {
const ccceInput: $Shape<CcceInput> = {};
//WHERE I THINK THE CHECK SHOULD GO (`ccceInput` is an object, with the `ccce.product` containing the users typed entry)
if (!object) {
return {};
}
// ccce input values
const ccceValues = object.attributeCollection.questions.reduce(
(acc, attribute) => {
const fieldEntry = ccceBeInformedFieldMap.get(attribute.key);
if (fieldEntry) {
acc[fieldEntry] = attribute.value;
}
return acc;
},
ccceInput
);
//check for null or empty string and if so hide "find goods button"
const productValueWithoutSpaces =
ccceValues.product && ccceValues.product.replace(/\s+/g, "");
const canClassify =
Object.values(ccceValues).every(Boolean) &&
Boolean(productValueWithoutSpaces);
return { canClassify, ccceValues };
};
export const useCcceEmbed = (
ccceResultAttribute: AttributeType,
onChange: Function
): CcceHook => {
const { object, form } = useFormObjectContext();
const [resultCode, setResultCode] = useState<string | null>(null);
const { canClassify, ccceValues } = getCcceValues(object);
const { handleSubmit } = useFormSubmit();
// data profile id is the 'api key' for 3ce
const dataProfileId = useSelector(
(state) => state.preferences[DATA_PROFILE_ID]
);
// data profile id is the 'api key' for 3ce
const isDebugMode = useSelector((state) => {
const value = state.preferences[CCCE_DEBUG_MODE_PREFERENCE];
try {
return JSON.parse(value);
} catch (error) {
throw new Error(
`3CE configuration error - non-boolean value for ${CCCE_DEBUG_MODE_PREFERENCE}: ${value}`
);
}
});
const [showModal, setShowModal] = useState<boolean>(false);
const handleCloseModal = useCallback(() => setShowModal(false), []);
const handleShowModal = useCallback(() => setShowModal(true), []);
// state value to keep track of a current active classification
const [classifyInProgress, setClassifyInProgress] = useState<boolean>(false);
// handle results from 3ce
const handleResult = useCallback(
(result) => {
if (result?.hsCode) {
onChange(ccceResultAttribute, result.hsCode);
setResultCode(result.hsCode);
setClassifyInProgress(false);
handleSubmit(form);
}
},
[ccceResultAttribute, form, handleSubmit, onChange]
);
const handleCancelClassify = useCallback(() => {
setClassifyInProgress(false);
handleCloseModal();
}, [handleCloseModal]);
// handle 3ce classify (https://github.com/3CETechnologies/embed)
const handleClassify = useCallback(
(event?: SyntheticEvent<any>) => {
if (event) {
event.preventDefault();
}
if (classifyInProgress || !canClassify) {
return;
}
const ccce = window.ccce;
if (!ccceValues || !ccce) {
throw new Error("Unable to classify - no values or not initialised");
}
setClassifyInProgress(true);
const classificationParameters = {
...ccceValues,
...DEFAULT_EMBED_PROPS,
};
ccce.classify(
classificationParameters,
handleResult,
handleCancelClassify
);
},
[
classifyInProgress,
canClassify,
ccceValues,
handleResult,
handleCancelClassify,
]
);
return {
allowForClassification: canClassify && !classifyInProgress,
classifyInProgress,
dataProfileId,
embedID: EMBED_ID,
handleCancelClassify,
handleClassify,
handleCloseModal,
handleShowModal,
isDebugMode,
resultCode,
shouldShowModal: showModal,
};
};
I have added a comment on where I think this logic should be handled (search "//WHERE I THINK..") - however, I'm unsure how to go from knowing the value of the users input, to checking for an enter press, I'm happy just to be able to console.log a user's key press, I should be able to tie up the logic from there, any advice would be really helpful.
TIA!

Display alreat message if object value exist in array of object in javascript

I want to display alert message if user type name into input field and checks if the value is same as the object value present in the array of object.
I'm using ReactJS. Here's my fake state :
const [persons, setPersons] = useState([
{ name: "Steve" },
{ name: "Tim" },
{ name: "Dan" },]);
const [newName, setNewName] = useState(""); //this state is for input value.
Form onSubmit is :
const handleSubmit = (e) => {
e.preventDefault();
const newPerson = {
name: newName,
};
setPersons(persons.concat(newPerson));
setNewName("");
If I'm understanding correctly, on submit, you want to see if the new name is already taken? You can use .some to see if that object already exists
const handleSubmit = (e) => {
e.preventDefault();
// will return true once it finds a matching entry, otherwise will return false
const exists = persons.some(person => person.name === newName);
if (exists) {
// code to show alert, probably something like `setError(true)`
} else {
const newPerson = { name: newName };
// probably want to clear the error, like `setError(false)`
setPersons(persons.concat(newPerson));
setNewName("");
}
}

Categories