In react native application i am using react navigation. I am send a object from one screen to other. After one section i am running a function which makes copy of my route parameter and modifying the copy. But my original parameter is also modifying. I do not want to modify the original object. How to avoid mutating parameters ?
Here is my parameter structure
{
id: 1
name: 'some name',
productOptions: [
{
productOptionId: 1
productOptionName: 'Option name'
options: [
{
name: 'some option name',
value: 12
},
{
name: 'some option name',
value: 12
},
{
name: 'some option name',
value: 12
}
]
},
{
productOptionId: 1
productOptionName: 'Option name'
options: [
{
name: 'some option name',
value: 12
},
{
name: 'some option name',
value: 12
},
{
name: 'some option name',
value: 12
}
]
}
]
}
Here is my screen code
const MyScreen({navigation, route}){
const product = route.params.product
const productOptions = route.params.productOptions
const [newOptionState, setNewOptionState] = useState([])
useEffect(() => {
setTimeout(()=>setPreSelected(), 1000)
}, [])
const setPreSelected = ()=>{
let tempProductOptions = [...productOptions]
tempProductOptions.map((item)=>{
if(item.options.length && item.options.length>1){
item.options.splice(1)
}
})
setNewOptionState(tempProductOptions)
}
}
Related
I am trying to add an onChange function that can add and delete options in the cascader menu. I would like to be able to select existing menu options and add options on to them as well.
My example data structure looks like this:
const [dataTitle, setDataTitle] = useState([
{
label: '2022',
value: '2022',
children: [
{
label: 'Fall',
value: 'Fall',
children: [
{
label: 'Week 1',
value: 'Week 1',
children: [
{
label: 'Practice 1',
value: 'Practice 1',
},
{
label: 'Practice 2',
value: 'Practice 2',
},
{
label: 'Practice 3',
value: 'Practice 3',
},
{
label: 'Practice 4',
value: 'Practice 4',
},
{
label: 'Game 1',
value: 'Game 1',
},
]
},
{
label: 'Week 2',
value: 'Week 2',
},
{
label: 'Week 3',
value: 'Week 3',
},
],
},
],
},
]);
I am using these onChange events below to add a 'create-new-option' button and to add the new option when prompted.
const handleLabelChange = (value, selectedOptions) => {
const lastOption = selectedOptions[selectedOptions.length - 1];
// Check if the last selected option has a value of 'create-new-option'
if (lastOption.value === 'create-new-option') {
// Prompt user for new option name
const newOptionName = prompt('Enter a name for the new option:');
// Add the new option to the options data
const newOption = {
label: newOptionName,
value: newOptionName,
};
let newDataTitle = [...dataTitle];
let parentOption = newDataTitle.find(o => o.value === lastOption.parentValue);
if (!parentOption) {
parentOption = { children: [] };
newDataTitle.push(parentOption);
}
// Check if parentOption.children is defined before trying to push
if (parentOption.children) {
parentOption.children.push(newOption);
}
setDataTitle(newDataTitle);
}
};
const addCreateNewOption = (options) => {
return options.map(option => {
return {
...option,
children: option.children
? [...addCreateNewOption(option.children), {value: 'create-new-option', label: 'Create new option', parentValue: option.value}]
: [{value: 'create-new-option', label: 'Create new option', parentValue: option.value}]
};
});
};
My issue is having the new option display in the correct spot and under the correct parents. It works correctly with the second level (I can add a 'Spring' Option and it correctly shows up under 2022 / Spring) but none others.
CodeSandbox Recreation
I'm trying to filter object with nested arrays by several criteria. Filtering options are generated dynamically and stored in array. This options values are theme id's in nested objects. If filtering options contain for example 2 id's values I need to show all objects that have that theme id's.
let data = {
'17 may': [
{
id: 31,
name: 'Test Name',
theme: {
id: 2,
name: 'Theme Test Name',
},
},
],
'18 may': [
{
id: 41,
name: 'Test Name',
theme: {
id: 2,
name: 'Theme Test Name',
},
},
{
id: 43,
name: 'Test Name',
theme: {
id: 3,
name: 'Theme Test Name',
},
},
],
'19 may': [
[
{
id: 51,
name: 'Test Name',
theme: {
id: 1,
name: 'Theme Test Name',
},
},
{
id: 52,
name: 'Test Name',
theme: {
id: 2,
name: 'Theme Test Name',
},
},
],
],
};
filteringOptions = [1,2]; // theme id's
I use filtering function for nested objects. It's working fine, but I dont' know how to pass more than one filtering option.
filterArray(array, filters) {
const filterKeys = Object.keys(filters);
return array.filter((item) => {
return filterKeys.every((key) => {
if (typeof filters[key] !== 'function') return true;
return filters[key](item[key]);
});
});
}
Filtering algorithm
const filteredByThemeId = {};
for (const day in data) {
filteredByTheme[day] = [];
this.data[day].map((item, index) => {
filteredByThemeId[day][index] = [
...filterArray(item, {
theme:
(theme) => {
if (!theme) return;
return theme.id === 2; // works fine, but I need to pass all values from filtering options array (options can contain 2, 5, 10 etc. values)
},
}),
];
});
}
Suppose you want to filter for all values in list called filterList = [2,5,10]. Instead of return theme.id === 2, you can try return filterList.includes(theme.id)
I have two arrays in ReactJS as follows
let document = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' }
]
let filterTypes = [{ value: 'abcd', id: 1 }]
How to generate the filtered array from this in ReactJS containing just one object with value abcd?
You could use Array.prototype.some() method inside Array.prototype.filter() method. Some method returns a Boolean value if at least one item in the array
passes the test by the given callback function.
const doc = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' },
];
const filterTypes = [{ value: 'abcd', id: 1 }];
const ret = doc.filter((x) => filterTypes.some((y) => y.value === x.value));
console.log(ret);
const docArray = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' },
];
const filterTypes = [{ value: 'abcd', id: 1 }];
console.log('-----non-matched----');
const nonmatched = docArray.filter(doc => filterTypes.findIndex(filt=> filt.value === doc.value));
console.log(nonmatched);
console.log('------matched----');
const matched = docArray.filter(doc => filterTypes.findIndex(filt=> filt.value !== doc.value));
console.log(matched);
I have two arrays as types and defaultTypes. I need to display types with default values array defaultTypes.
const types = [
{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
const defaultTypes = [
{
Id: 1,
Name: 'Default value 1'
},
{
Id: 2,
Name: 'Default value 2'
}
]
If in types does not exist some of default types (in this case Id: 1 does not exist in the types array). I need to add that object in types array.
Expected result will be:
const expectedTypes = [
{
Id: 1,
Name: '-'
},
{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
Objects with Ids 1 and 2 always need to be in expectedTypes.
const expectedTypes = types.concat(
defaultTypes.filter(
type => !types.some(t => t.Id == type.Id)
));
explanation: basically what you want is types + stuff in defaultTypes that are not in types already.
Try this one:
let types = [{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
const defaultTypes = [{
Id: 1,
Name: 'Default value 1'
},
{
Id: 2,
Name: 'Default value 2'
}
];
defaultTypes.forEach(dt => {
if (!types.some(t => t.Id === dt.Id)) {
types.push(dt);
}
});
types = types.sort((a, b) => a.Id - b.Id);
console.log(types);
Use this code and try
var _ = require('lodash');
defaultTypes.forEach(type => {
if (!_.find(types, { Id: type.Id })) {
types.push({ Id: type.Id, Name: '-' });
}
});
You can first use create a Set using map() which will contain its of elements in types.
Then loop through the defaultTypes and check if the Set contain the Id. If doesn't then push() it to types
At the end use sort() to order the elements by Id
const types = [ { Id: 2, Name: 'Some value here' }, { Id: 3, Name: 'Some value here' }, { Id: 4, Name: 'Some value here' } ];
const defaultTypes = [ { Id: 1, Name: 'Default value 1' }, { Id: 2, Name: 'Default value 2' } ]
let ids = new Set(types.map(x => x.Id));
defaultTypes.forEach(x => {
if(!ids.has(x.Id)) types.push(x)
})
types.sort((a,b) => a.Id - b.Id)
console.log(types)
Purpose Of Set
The purpose of Set is to make the time complexity liner O(n). If you don't use Set you will need to use some() on the types in each loop. So the time-complexity would be O(m*n)
Set.prototype.has has time complexity O(1)
You could reduce the elements in the wanted order with a Map and get all values as result.
const
types = [{ Id: 2, Name: 'Some value here' }, { Id: 3, Name: 'Some value here' }, { Id: 4, Name: 'Some value here' }],
defaultTypes = [{ Id: 1, Name: 'Default value 1' }, { Id: 2, Name: 'Default value 2' }],
result = Array.from([...defaultTypes, ...types]
.reduce((m, o) => m.set(o.Id, Object.assign({}, m.get(o.Id), o)), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am new to Quasar and Vue. Could someone explain to me how to solve my task?
Briefly about the task:
(1) I have a q-tree element which represents the folder structure at the left side of a screen [ref.1]
(2) Here is a folder structure [ref.2]
(3) When the user clicks on any element in this folder structure, then he will see a new component on the right side with all children elements of clicked one in a grid layout.
This is what do I have now.
[ref.1] treeComponent.vue
<template>
<q-tree
:nodes="documents"
#click="getId"
node-key="id" >
</q-tree>
</template>
<script>
var documents = require('./documents')
module.exports = {
data: function () {
return {
selectedDoc: x,
documents: documents
}
},
methods: {
getId: function () {
const x = this.getNodeByKey('id')
consol.log(x)
}
}
}
</script>
[ref.2] documents.js
module.exports = [
{
id: '1',
label: 'My Documents',
icon: 'folder',
children: [
{
id: '01',
label: 'Dir 1',
children: [
{ id: '0001', label: 'Doc 1'},
{ id: '0002', label: 'Doc 2'}
]
},
{
id: '02',
label: 'Dir 2',
children: [
{ id: '0003', label: 'Doc 3'},
{ id: '0004', label: 'Doc 4'}
]
},
{
id: '103',
label: 'Dir 3',
children: [
{ id: '0005', label: 'Doc 5'},
{ id: '0006', label: 'Doc 6'},
{ id: '0007', label: 'Doc 7'}
]
}
]
}
]
you need to replace id by key.after this add this handler for each node
handler: (node) => this.onclick(node)
then add this method in methods
onclick(node) {
alert(node.key)
},
this will display id of perticular node
So, the main problem was related to not good enough acquainted with Quasar framework.
Here is my answer to this question:
<template>
<button v-on:click = "showNodeSelected">showClickedNode</button>
<q-tree
:nodes = "documents"
:selected.sync = "selected"
node-key="id"
/>
</template>
<script>
var documents = require('./documents')
module.exports = {
data: function () {
return {
selected: null,
documents: documents
}
},
methods: {
showNodeSelected: function () {
console.log(this.selected)
}
}
}
</script>