So I have an Object that is empty and after the user submits the value, it is saved.
let state = reactive({
id: '',
name: '',
status: 0,
}
after the submit, I would like to save my values.
onResult(() => {
state.id = '1'
state.name = 'Name'
state.status = 1
})
I would like to swap the complete object like I would do it in a ref, like:
state.value = {
id: '1,
name: 'Name',
state: 1
};
Is there any shorthand when using reactive?
This is not specific to reactive objects and would require to clear an object, which is inefficient.
This is the case for a ref. It can be unwrapped in a script if needed to skip value access:
const stateRef = ref({...})
const stateObj = shallowReadonly(stateRef);
Related
I'm using Vue 3 for sending POST data to my API. The objects look like
const externalResults: ref(null)
const resource = ref({
id: null,
name: null,
state: {}
})
Before sending the data to the API I'm parsing the resource object to avoid sending a nested object related to state property. So the payload sent looks like
{
id: 1,
name: 'Lorem ipsum',
state_id: 14
}
The API returns a 422 in case of missing/wrong data
{
"message":"Some fields are wrong.",
"details":{
"state_id":[
"The state_id field is mandatory."
]
}
}
So here comes the question: how can I rename object keys in order to remove always the string _id from keys?
Since I'm using vuelidate I have to "map" the returned error details to model property names. Now I'm doing this to get details once the request is done
externalResults.value = e.response.data.details
but probably I will need something like
externalResults.value = e.response.data.details.map(item => { // Something here... })
I'd like to have a 1 line solution, no matter if it uses ES6 or lodash.
Please note that state_id is just a sample, there will be many properties ended with _id which I need to remove.
The expected result is
externalResults: {
"state":[
"The state_id field is mandatory."
]
}
I don't know how long you allow your one-liners to be, but this is what I come up with in ECMAScript, using Object.entries() and Object.fromEntries() to disassemble and reassemble the object:
const data = {
id: 1,
name: 'Lorem ipsum',
state_id: 14
};
const fn = (x) => Object.fromEntries(Object.entries(x).map(([k, v]) => [k.endsWith('_id') ? k.slice(0, -3) : k, v]));
console.log(fn(data));
You can shorten it a little more by using replace() with a regex:
const data = {
id: 1,
name: 'Lorem ipsum',
state_id: 14
};
const fn = (x) => Object.fromEntries(Object.entries(x).map(([k, v]) => [k.replace(/_id$/, ''), v]));
console.log(fn(data));
If you use lodash, you can go shorter still by using the mapKeys() function:
const data = {
id: 1,
name: 'Lorem ipsum',
state_id: 14
};
const fn = (x) => _.mapKeys(x, (v, k) => k.replace(/_id$/, ''));
console.log(fn(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
I wrote this code to return a list of skills. If the user already has a specific skill, the list-item should be updated to active = false.
This is my initial code:
setup () {
const user = ref ({
id: null,
skills: []
});
const available_skills = ref ([
{value: 'css', label: 'CSS', active: true},
{value: 'html', label: 'HTML', active: true},
{value: 'php', label: 'PHP', active: true},
{value: 'python', label: 'Python', active: true},
{value: 'sql', label: 'SQL', active: true},
]);
const computed_skills = computed (() => {
let result = available_skills.value.map ((skill) => {
if (user.value.skills.map ((sk) => {
return sk.name;
}).includes (skill.label)) {
skill.active = false;
}
return skill;
});
return result;
})
return {
user, computed_skills
}
},
This works fine on the initial rendering. But if I remove a skill from the user doing
user.skills.splice(index, 1) the computed_skills are not being updated.
Why is that the case?
In JavaScript user or an object is a refence to the object which is the pointer itself will not change upon changing the underling properties hence the computed is not triggered
kid of like computed property for an array and if that array get pushed with new values, the pointer of the array does not change but the underling reference only changes.
Work around:
try and reassign user by shadowing the variable
The computed prop is actually being recomputed when you update user.skills, but the mapping of available_skills produces the same result, so there's no apparent change.
Assuming user.skills contains the full skill set from available_skills, the first computation sets all skill.active to false. When the user clicks the skill to remove it, the re-computation doesn't set skill.active again (there's no else clause).
let result = available_skills.value.map((skill) => {
if (
user.value.skills
.map((sk) => {
return sk.name;
})
.includes(skill.label)
) {
skill.active = false;
}
// ❌ no else to set `skill.active`
return skill;
});
However, your computed prop has a side effect of mutating the original data (i.e., in skill.active = false), which should be avoided. The mapping above should clone the original skill item, and insert a new active property:
const skills = user.value.skills.map(sk => sk.name);
let result = available_skills.value.map((skill) => {
return {
...skill,
active: skills.includes(skill.label)
}
});
demo
slice just returns a copy of the changed array, it doesn't change the original instance..hence computed property is not reactive
Try using below code
user.skills = user.skills.splice(index, 1);
I have the following array of objects:
const originalArray = [
{name: 'name1', value: 10},
{name: 'name2', value: 20}
]
And the following object
names = {
name1: 'generic_name_1',
name2: 'generic_name_2'
}
I would like the first array to be transformed like this:
[
{name: 'generic_name_1', value: 10},
{name: 'generic_name_2', value: 20}
]
What I have tried so far:
const replaceName = (names, obj) => {
if(obj['name'] in names){
obj['name'] = names[obj['name']];
}
return obj;
}
const modifiedArray = R.map(replaceName(names), originalArray)
Is there a more ramda-ish way to do this?
Using native JS inside Ramda functions is not unramdaish. The only problem in your code is that you mutate the original object - obj['name'] = names[obj['name']];.
I would use R.when to check if the name exists in the names object, and if it does evolve the object to the new name. If it doesn't the original object would be returned.
const { flip, has, prop, map, when, pipe, evolve } = R
const hasProp = flip(has)
const getProp = flip(prop)
const fn = names => map(when(
pipe(prop('name'), hasProp(names)),
evolve({
name: getProp(names)
})
))
const originalArray = [{"name":"name1","value":10},{"name":"name2","value":20},{"name":"name3","value":30}]
const names = {"name1":"generic_name_1","name2":"generic_name_2"}
const result = fn(names)(originalArray)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
I wouldn't use any Ramda functions for this. I would simply avoid mutating the original, perhaps with code like this:
const transform = (names) => (arr) => arr .map (
({name, ... rest}) => ({name: names [name] || name, ... rest})
)
const originalArray = [{name: 'name1', value: 10},{name: 'name2', value: 20}]
const names = {name1: 'generic_name_1',name2: 'generic_name_2'}
console .log (
transform (names) (originalArray)
)
I have the following data structure in vuex file:
state:{
info:[
{
name: 'Some field 1',
value: '',
pattern: /.+/,
//status: ''
},
{
name: 'Some field 2',
value: '',
pattern: /.+/,
// status: ''
}
]
I would like every object to have a field status: ''.But I do not want to duplicate the code. In Vue component I wrote for this:
beforeMount(){
// add new fuild
}
But this way does not work in Vuex.
beforeMount(){
console.log('does not work');
for (let i = 0; i < this.info.length; i++) {
this.$set(this.state.info[i], 'status', '');
}
}
How to add a new field into state dynamically?
In a mutation just do something like this:
state.info = state.info.map(x => ({
...x,
status: ''
})
I have a state like this:
this.state ={
photos: [
{ description: 'someDescription', id: 1 },
{ description: 'someDescription', id: 2 },
{ description: 'someDescription', id: 3 }
]
}
How can I update one of the descriptions only?
Or I have to do something like
this.setState({ photos: newArrayOfObjectsWithOnlyOneUpdatedDescription })
You can create a funtion to do it for you like this:
const updatePhoto = (id, desc) =>
this.state.photos.map((obj) =>
obj.id === id ? Object.assign(obj, { description: desc }) : obj)
map function will return a new array, so you won't need to do a manual state cloning stuff.
Then reuse it as you need it:
this.setState({ photos: updatePhoto(2, 'new desc') })
You can create copy of state, then update copied state and setState
let stateCopy = Object.assign({}, this.state); // get the current state copy
stateCopy.photos = stateCopy.photos.slice(); // get photos object
stateCopy.photos[key] = Object.assign({}, stateCopy.photos[key]);
stateCopy.photos[key].description = 'new decription'; // update description of specific key
this.setState(stateCopy); // set state