How to properly reset Vue Composition Api's reactive values - javascript

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.

Related

Object element returning undefined with addEventListener

I am making a simple form which requests the user to input their project name and their name, along with some other info.
But each type of project has a different page, so to avoid copying and pasting the same getElementById and addEventListener functions in each page, I've made a module with those functions so every page handles it as needed. This is one of the pages:
// (imports)...
let project = {
author: null,
name: null,
mission: {
file: null,
path: null,
},
sd: {
code: null,
path: null,
},
modloaderfolder: null,
};
window.addEventListener("DOMContentLoaded", () => {
project.mission = handleMission();
project.sd = handleSD();
project.modloaderfolder = handleModloader();
project.name = handleName();
project.author = handleAuthor();
// ...
The problem is that the objects' elements are returning undefined in the two following functions:
export function handleName() {
const project = {};
const txt_name = document.getElementById("name");
txt_name.addEventListener("change", () => {
project.name = txt_name.value;
});
return project.name;
}
export function handleAuthor() {
const project = {};
const txt_author = document.getElementById("author");
txt_author.addEventListener("change", () => {
project.author = txt_author.value;
});
return project.author;
}
// Returns undefined
Whats intriguing for me is that some other functions are working as intended, I can't find out why. These are the corretly working functions:
export function handleSD() {
const project = { sd: {} };
const input_sd = document.getElementById("sd");
input_sd.addEventListener("change", () => {
document.getElementById("sel-sd").innerHTML = "";
Array.from(input_sd.files).forEach((file) => {
document
.getElementById("sel-sd")
.insertAdjacentHTML("beforeend", `<option>${file.name}</option>`);
});
if (!input_sd.files[0]) return;
const path = input_sd.files[0].path;
project.sd.path = path.substring(0, path.lastIndexOf("\\")) + "\\";
project.sd.code = project.sd.path.substring(
project.sd.path.lastIndexOf("\\") - 5,
project.sd.path.length - 1
);
});
return project.sd;
}
// This function correctly returns "sd: { path: ..., code: ...}"
What I noticed is that by returning an object, it returns and updates correctly for each change, but while returning an object's element, it aways returns undefined.
which is empty and nothing will change it because copying a primitive value is by value but the object that holds the key of the string, and as soon as the onchange function is activated it changes the value of your key in the object and it automatically changes in your object too because it is copied by Reference.
You can read more about this topic here

Using forEach on a nested object key react javascript

I have a nested object:
const refsObject = {
refOne: {
current: {
validate: function()
}
},
refTwo: {
current: {
validate: function()
}
}
};
I need to run input field validation using a single method that loops through each nested object of objects and invokes the validate method.
What I have tried up until now:
const splitObject = o => Object.keys(o).map(e => ({ [e]: o[e] }));
splitObject.forEach(ref => ref.current && ref.current.validate());
SplitObject returns me an array of objects with all the objects inside refsObject. Once I do forEach on splitObject it becomes undefined since ref.current is inside the nested object key "refOne" which is dynamic so I cannot hardcode. Any suggestion helps!
Is this what you're looking for?
const refsObject = {
refOne: {
current: {
validate: function() {
console.log('validate1');
}
}
},
refTwo: {
current: {
validate: function() {
console.log('validate2');
}
}
}
};
Object.values(refsObject).map(refs => refs.current.validate());
Run the validations on the original refsObject by taking the values, and iterating them with Array.forEach(). Use conditional chaining ?. to call the function in case current might be undefined:
const refsObject = {refOne:{current:{validate(){console.log('refOne')}}},refTwo: {current: {validate() {console.log('refTwo')}}}};
const runValidations = o => Object.values(o)
.forEach(ref => ref.current?.validate());
runValidations(refsObject);

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.

calling a function from a const value

I have an initial state const item that looks like this:
const INITIAL_STATE = {
endPoint: { street: '', coordinates: [] }, //[13.3969, 52.5182]
startingPoint: { street: '', coordinates: [] }, //[13.413215, 52.521918]
favouritePoint: { street: '', coordinates: [] },
favouriteLocations: {getFavouritePlaces()},
// favouriteLocations: [
// {
// name: 'Zu Hause',
// street: 'Müllersweg',
// coordinates: [8.217462, 53.13975], //[8.258844, 53.119525],
// },
// {
// name: 'Büro',
// street: 'Philipp-Reis-Gang',
// coordinates: [8.258844, 53.119525], //[8.217462, 53.13975],
// },
// {
// name: 'KaffeeHaus',
// street: 'Cloppenburgerstr.',
// coordinates: [8.211, 53.113],
// },
// ],
addressesFoundList: [],
};
Instead of the hardcoded value, I am trying to call a function for favouriteLocations that will return an object of the same type. However, currently this does not call my function.
My function looks like this:
const getFavouritePlaces = () => {
return ...
}
Later on, I will be using this initial state for my redux setup.
I don't think you need the brackets around the function call.
Change favouriteLocations: {getFavouritePlaces()}, To favouriteLocations: getFavouritePlaces(),.
As mentioned there's syntax error.
Alternativ 1 - Spreading the function containing the desired object:
const INITIAL_STATE = {
favouriteLocations: {...getFavouritePlaces()}
};
Alternativ 2 - Run the function that will return the desired object:
const INITIAL_STATE = {
favouriteLocations: getFavouritePlaces()
};
You should declare it like this:
const getFavouritePlaces = () => {
console.log('test');
}
const INITIAL_STATE = {
favouriteLocations: getFavouritePlaces
}
INITIAL_STATE.favouriteLocations();
This will work even if your fucntion recevies a variable like:
const getFavouritePlaces = (x) => {
console.log(x);
};
const INITIAL_STATE = {
favouriteLocations: getFavouritePlaces
}
INITIAL_STATE.favouriteLocations('test');

Copy state object without some fields

I need to transfer state of a component to its parent component, but I don't need to transfer all fields.
What I currently do:
submitHandler = (e) => {
e.preventDefault();
const newState = Object.keys(this.state).map(item => {
if(item !== 'errors')
{
return { item: this.state[item] }
}
});
console.log(newState);
this.props.onChange(newState);
}
Obviously it is not what I need.
state = {
errors: {
fio: '',
email: '',
phone: ''
},
owner: owner.Company,
fio: null,
company: null,
phone: null,
fax: null,
email: null,
adress: null
}
I need to transfer all field except errors. How can I do that?
You can use the rest operator for making it work :)
const { errors, ...newState } = this.state;
this.props.onChange(newState);
I put an example here :) https://repl.it/#EQuimper/PleasantTrimDeclarations
Object destructuring with the rest operator provides a convenient way to copy objects, while omitting specific fields. In the example below, newState will be a copy of this.state, minus the errors property:
submitHandler = e => {
e.preventDefault();
const { errors, ...newState } = this.state;
this.props.onChange(newState);
};

Categories

Resources