Why i cannot assign values to destructured object variables? - javascript

I have form in my website with onSubmit eventListener, so when user submits the form getCurrencyData function is executed. inside getCurrencyData function im checking whether the user entered value or not, if yes then im making apicall and destructuring generalCurrencyInfo object. The problem is that i cannot assign values to destructured object variables.
class App extends Component {
constructor(props) {
super(props);
this.state = {
generalCurrencyInfo: {
fullName: undefined,
name: undefined,
imageUrl: undefined,
price: undefined,
error: false
}
}
}
getCurrencyData = async (e) => {
e.preventDefault();
const CURRENCYNAME = e.target.elements.currencyName.value.toUpperCase();
//Checks if currency name is not empty
if (CURRENCYNAME) {
const APICALL = await fetch(`url`);
const DATA = await APICALL.json();
let generalCurrencyInfo = {
fullName:undefined,
name: undefined,
imageUrl: undefined,
price: undefined,
error: false
}
//this destructuring doesn't work
let {fullName, name, imageUrl, price, error} =generalCurrencyInfo;
if (DATA.Message === "Success") {
fullName = DATA.Data[0].CoinInfo.FullName;
name = DATA.Data[0].CoinInfo.Name;
imageUrl = `url`;
price = "price";
error = false;
}
this.setState({
generalCurrencyInfo: generalCurrencyInfo
})
}
}
render() {
return (
);
}
}

You have created 5 new variables here:
let {fullName, name, imageUrl, price, error} =generalCurrencyInfo;
Then you have changed this variables, but not generalCurrencyInfo object:
if (DATA.Message === "Success") {
fullName = DATA.Data[0].CoinInfo.FullName;
name = DATA.Data[0].CoinInfo.Name;
imageUrl = `url`;
price = "price";
error = false;
}
Here you set generalCurrencyInfo, what was not changed:
this.setState({
generalCurrencyInfo: generalCurrencyInfo
})
This will be fine:
this.setState({
fullName,
name,
imageUrl,
price,
error,
})

You can just reassign the values to your generalCurrencyInfo object, so no need to destructure:
// reassign values
if (DATA.Message === "Success") {
generalCurrencyInfo.fullName = DATA.Data[0].CoinInfo.FullName;
generalCurrencyInfo.name = DATA.Data[0].CoinInfo.Name;
generalCurrencyInfo.imageUrl = `url`;
generalCurrencyInfo.price = "price";
generalCurrencyInfo.error = false;
}
// or using the spread operator
if (DATA.Message === "Success") {
generalCurrencyInfo = {
...generalCurrencyInfo,
fullName: DATA.Data[0].CoinInfo.FullName,
name: DATA.Data[0].CoinInfo.Name,
imageUrl: `url`,
price: "price",
error: false,
};
}
But if you landed on this page looking to find out how to re-assign a value to a destructured object, you might want to check out this question: Is it possible to destructure onto an existing object? (Javascript ES6)

Related

I want to loop in an array in the state and check if the input is exist in it

I tried to build this method addgamer() to check if the username exists in the gamers array onClick add button and if he is , i want it don't add his info as an object in the array, i want to know why it didn't work ?
....i created this enterdata() method to get the values of these three gamer info onChange the values of their inputs
class App extends Component {
state= {
gamer:{
FirstName:"",
LastName: "",
UserName: "",
},
gamers:[],
}
enterdata = (event)=> {
const {name, value} = event.target;
this.setState((prevstate)=>({
gamer: {...prevstate.gamer,[name] : value},
}))
}
addgamer = (event) =>{
event.preventDefault();
for(let i = 0;i<this.state.gamers.length; i++){
if(this.state.gamer.UserName === this.state.gamers[i].UserName){
return false;
}else{
this.setState(prevstate =>({
gamers: [...prevstate.gamers, this.state.gamer],
gamer: {FirstName:"", LastName: "", UserName: ""},
}))
}
}
}
The issue here is that you are adding the gamer every time the username is not found. What you should do is set a flag to see whether the username was found in the gamers list or not, and then do the setState to add the new gamer if the username was not found, like so:
let found = false;
for(let i = 0;i<this.state.gamers.length; i++){
if(this.state.gamer.UserName === this.state.gamers[i].UserName){
found = true;
break;
}
}
// alternatively: let found = this.state.gamers.find(gamer => this.state.gamer.UserName === gamer.UserName)
if (!found) {
this.setState(prevstate =>({
gamers: [...prevstate.gamers, this.state.gamer],
gamer: {FirstName:"", LastName: "", UserName: ""},
}))
}

Javascript - Get object fields using a given array of keys

Given this object:
const userData = {
avatar: undefined,
name: "Raul",
username: "raulito",
celebrity: true
}
I need to implement a method that receives a list of keys (i.e., ["avatar", "name", "username"]) and get the corresponding values of the userData object, ignoring undefined values.
How can I do this using modern javascript syntax?
function denormalizeUserData(userData, ...fields) {
const denormalized = {};
// For each key (field), get its value from userData, ignoring if undefined
return denormalized;
}
So, if I do:
denormalizeUserData(userData, "avatar", "name");
The method must return me:
{
name: "Raul,
}
Ignoring avatar, as it is undefined.
This is my attempt. I need modern syntax.
const userData = {
avatar: undefined,
name: "Raul",
username: "raulito",
celebrity: true
}
function denormalizeUserData(userData, ...fields) {
const denormalized = {};
fields.forEach((key) => {
const value = userData[key];
if(typeof value !== "undefined") {
denormalized[key] = value;
}
})
return denormalized;
}
console.log(denormalizeUserData(userData, "celebrity", "name", "avatar"))
function denormalizeUserData(userData, ...fields) {
const denormalized = {};
for (const field of fields) {
if (userData[field] !== undefined) denormalized[field] = userData[field];
}
return denormalized;
}
Edit: in case someone says a code-only answer is blah blah blah
This is simple enough to be a simple code block.
You can get the object property/value pairs with Object.entries, then use Array.filter to filter out the pairs whose property name is not included in fields and whose value is undefined, then use Object.fromEntries to convert it back to an object.
const userData = {
avatar: undefined,
name: "Raul",
username: "raulito",
celebrity: true
}
function denormalizeUserData(userData, ...fields) {
return Object.fromEntries(Object.entries(userData).filter(e => fields.includes(e[0]) && e[1] != undefined))
}
console.log(denormalizeUserData(userData, "avatar", "name"))
Grab the Object.entries and build a new object if there is a value, and if the args array includes the key.
const userData = {
avatar: undefined,
name: "Raul",
username: "raulito",
celebrity: true
};
function denormalizeUserData(obj, ...args) {
const out = {};
for (let [key, value] of Object.entries(obj)) {
if (value && args.includes(key)) {
out[key] = value;
};
}
return out;
}
console.log(denormalizeUserData(userData));
console.log(denormalizeUserData(userData, 'avatar', 'name'));
console.log(denormalizeUserData(userData, 'avatar', 'name', 'celebrity'));

Change Nested State Value With A Single Function? (javascript/React)

I have some react user privilege state data I need to manage. I would like the ability to change the object privileges based on their property through a dynamic function. I'm not sure how to target the specific nested privilege property to change the value. Is this possible?
Question: How can I change the value of a nested privilege property to the functions type and value parameter?
Heres an Example:
const [userPrivilages, setUserPrivilages] = useState([{
_id: "123"
privilages: {
edit: true, //before!
share: true,
del: false
}
},
{
...more users
}
])
//my attempt
const changePrivilage = (type, value) => {
const newPrivilages = userPrivilages.map(user => {
return {
...user,
privilages: {
...privilages,
//change the privilage of "type" from the functions parameter to the value parameter
}
}) setUserPrivilages(newPrivilages)
}
changePrivilage("edit", false)
Desired output:
const [userPrivilages, setUserPrivilages] = useState([{
_id: "123"
privilages: {
edit: false, //After!
share: true,
del: false
}
},
{
...more users
}
])
Thanks!
You can use [] to refer to variable as a key like below:
const changePrivilage = (type, value) => {
const newPrivilages = userPrivilages.map(user => {
return {
...user,
privilages: {
...user.privilages,
[type]: value // here it is !!!
}
}) setUserPrivilages(newPrivilages)
}
Try this :
(see comments for understanding code)
const changePrivilage = (type,value) => {
const newUserPrivilages = userPrivilages.map(user => {
let newPrivilages = user.privilages; // get old privilages of user
newPrivilages[type] = value; // update type with new value
return {
...user,
privilages: newPrivilages, // set privilages as newPrivilages
};
});
setUserPrivilages(newUserPrivilages);
};
Note : this will change properties for all users. If you want to update only for specific user, pass _id as well to changePrivilage and execute newPrivilages[type] = value; // update type with new value inside if condition comparing user _id.

How to properly reset Vue Composition Api's reactive values

I'm wondering how should I reset a reactive in vuejs setup? (i know if change it to the ref and using view.value will solve this problem, but there should be an answer to this for using reactive)
setup(props, context){
// states
const DataTable = reactive((null as unknown) as DataTable);
const PolicyForm = reactive((null as unknown) as PolicyForm);
let view = reactive(resetViewState());
let config = reactive(
(resetPreRegisterConfig() as unknown) as PreRegisterConfig
);
// methods:
const fetchProfilelist = (
pagination: Pagination{ page:1, size:15},
sort_label: string = ""
) => {
DataTable.fetchTablelist(api_fetchProfilelist, pagination, sort_label);
};
const pageRefresh = () => {
view = resetViewState(); // 👈
config = resetPreRegisterConfig();
fetchProfilelist();
};
return {
DataTable,
PolicyForm,
view,
config,
fetchProfilelist,
pageRefresh
}
You can use Object.assign:
setup() {
const initialState = {
name: "",
lastName: "",
email: ""
};
const form = reactive({ ...initialState });
function resetForm() {
Object.assign(form, initialState);
}
function setForm() {
Object.assign(form, {
name: "John",
lastName: "Doe",
email: "john#doe.com"
});
}
return { form, setForm, resetForm };
}
See it live on codesandbox
credits: taken from here
Object.assign didn't work for me. (Maybe because I used a shim for the Composition API in Nuxtjs 2?) For anybody that run into the same problem: I had to use a compact loop.
setup() {
const initialState = {
name: "",
lastName: "",
email: ""
};
const form = reactive({ ...initialState });
function resetForm() {
for (const [key, value] of Object.entries(initialState)) {
form[key] = value
}
}
function setForm(values = {name: "John", lastName: "Doe", email: "john#doe.com"}) {
// only loop with the supported keys of initial state
for (const key of Object.keys(initialState)) {
form[key] = values[key]
}
}
return { form, setForm, resetForm };
}
Citing from the official Vueland Discord server:
"For what I know, reactive is the old way we use to do reactivity from the Classic API, so to reset the values should be something like:"
const myData = reactive({
foo: true,
bar: ''
})
function resetValues () {
myData.foo = true
myData.bar = ''
}
Therefore, if you don't change properties you should be able to use Object.assign(). (Correct me if I'm wrong)
How about use ref instead of reactive?
const myData = ref({ xxx: 11 })
// ... After many operations on myData
// resetData
myData.value = { xxx: 11 }
The disadvantage is that you need to add .value when using it in script.
But this is the same as reactive in vue template.
If you have deep objects you can use this trick to reset the values converting them to JSON
setup(){
const form = ref({
order: '',
user:{},
});
const defaultForm = JSON.parse(JSON.stringify(form));
form.value.user = {firstname:"Joe", lastname:"Doe"};
const onSubmit = () => {
// Reset values to default
form.value = JSON.parse(JSON.stringify(defaultForm));
}
}
If you do not want to use ref and want to reset value of a reactive variable then you have to take one key variable for reference in the reactive variable, because reinitializing reactive variable directly will cause to loose reactivity in the process.
So to reset the value use extra key variable in reactive variable, see code as below
setup() {
const initialState = {
name: "",
email: ""
};
const form = reactive({ data: ...initialState });
function resetForm() {
form.data = { ...initialState };
}
function setForm() {
form.data = {
name: "Bahubali",
email: "bahubali#mahismati.com"
});
}
return { form, setForm, resetForm };
}
So basically you are taking data as key of your reactive variable and when you want to reset or set your values you just need to change the form.data and it will be reactive and refreshes the elements which uses form.data.

How can I access a nested object inside an array to validate it?

This is my schema:
detail: [{
quantity: Number,
product:{
name: String,
code: Number,
price: Number
},
subtotal: Number
]}
This is my validations method
const validations = values => {
const errors = {
product: {}
}
if(!values.detail ||
!values.detail.length){
errors.detail = {_error: 'at
least one item must be
required'}
}
else{
const detailArrayErrors = []
values.detail.forEach(
(item,itemIndex) =>{
const detailErrors = {}
if(!item || !item.quantity){
detailErrors.quantity
='Required'
detailArrayErrors[itemIndex]=
detailErrors
}
if(!item || !item.subtotal){
detailErrors.subtotal
= 'required'
detailArrayErrors[itemIndex]
= detailErrors
}
//How can I access product
// in validations method
})
if(detailArrayErrors.length)
errors.detail =
detailArrayErrors
}
return errors;
}
export default validations;
product is my nested json object inside detail. Detail is an array. I want to validate product. How can I access a nested json object inside an array for validate it?
I've tried using for... of, but it makes not results.
I was searching on web but I couldn't find nothing.
How can I do that?
Anyone who knows?
values.detail.forEach(d=> console.log(d.product));
To get array of invalid e.g.:
let invalidItems = values.detail.filter(d => !d.product || !d.quantity ||
!d.product.name);
To do something on each item in array:
this.values.detail.forEach(i =>
{
let detailErrors = {'quantity': null, product: null};
if (!i.quantity)
{
detailErrors.quantity= 'Required'
}
if (!i.product)
{
detailErrors.product = 'Required'
}
if (i.product && !i.product.price)
{
detailErrors.product = {'price' :'Required'}
}
});

Categories

Resources