Vue.js Asynchronous Traversing - javascript

Open the page, get sexList and clientList form the server
Traverse 2 sets of data, push the sexText into the clientList
But the code is not working. How can I modify my code?
Code is here:
let sexList = [// store data: sexList
{
code: 0,
sexText: 'female',
},
{
code: 1,
sexText: 'male',
}
]
let clientList = [// index data: clientList
{
name: 'john',
sexCode: 1,
},
{
name: 'joe',
sexCode: 0,
}
]
mounted() {
this.$store.dispatch('getSexList')// get sexList form the server
getClientList({data: 'clients'}).then((res) => {
if(res.data.success) {
this.clientList = res.data.data// get clientList form the server
}else {
this.$message.error(res.data.message)
}
}).catch((err) => {
console.log(err)
})
},
watch: {
/*
watch clientList,traversing cientList and sexList,push the sexText into the clientList
*/
clientList(val) {
if(val && val.length > 0) {
val.map((item) {
this.$store.getters.sexList.map((sex_item) => {
if(sex_item.sexCode == item.sexCode) {
item.sexText = sex_item.sexText
}
})
})
}
},
}
After edit, it is working
setTimeout(() => {
getClientList({data: 'clients'}).then((res) => {
if(res.data.success) {
this.clientList = res.data.data// get clientList form the server
}else {
this.$message.error(res.data.message)
}
}).catch((err) => {
console.log(err)
})
}, 1000)
let clientList = [// index data: clientList
{
name: 'john',
sexCode: 1,
sexText: 'male',
},
{
name: 'joe',
sexCode: 0,
sexText: 'female',
}
]
Have another way?

Related

How to restructure object array to nested arrays?

The structure of an object array looks like this:
[
{ _id: "id1", metadata: { data: ["somedata1"], link: [] } }
{ _id: "id2", metadata: { data: ["somedata2"], link: ["id2", "id3"] } }
{ _id: "id3", metadata: { data: ["somedata3"], link: ["id2", "id3"] } }
{ _id: "id4", metadata: { data: ["somedata4"] } }
]
As you can see, there is an optional link key, which connects two objects. Now I need to convert the object to array elements, which merges the connected datasets. So the result should look like this:
[
[
{ _id: "id1", metadata: { data: ["somedata1"], link: [] } }
],
[
{ _id: "id2", metadata: { data: ["somedata2"], link: ["id2", "id3"] } },
{ _id: "id3", metadata: { data: ["somedata3"], link: ["id2", "id3"] } }
],
[
{ _id: "id4", metadata: { data: ["somedata4"] } }
]
]
I think I would iterate through all objects, but I don't know how to merge the linked objects into one array element without getting duplicates.
const result = []
data.map(d => {
if (!d.metadata.link?.length)
result.push([d])
else
result.push(
data.getFiles.filter((item) => d.metadata.link.indexOf(item._id) !== -1)
)
// but this would result in a duplicate array, as id2 and id3 have the same link content
})
if you just want to loop on an array you can directly use array.forEach
An idea can be to just add an if before push in result array to check if data have already been added for sample with array.some
if (!result.some(oneArr => oneArr.some(oneData => oneData._id === d._id)))
const data = [
{ _id: "id1", metadata: { data: ["somedata1"], link: [] } },
{ _id: "id2", metadata: { data: ["somedata2"], link: ["id2", "id3"] } },
{ _id: "id3", metadata: { data: ["somedata3"], link: ["id2", "id3"] } },
{ _id: "id4", metadata: { data: ["somedata4"] } }
];
const result = [];
data.forEach(d => {
if (!d.metadata.link?.length) {
result.push([d])
} else {
if (!result.some(oneArr => oneArr.some(oneData => oneData._id === d._id)))
result.push(
data.filter((item) => d.metadata.link.indexOf(item._id) !== -1)
)
}
});
console.log(result);
I think below way object will not get duplicate. data will group as link values. This approach does n't have much complexity. It will be O(N)
I hope this is what you're looking for.
const data = [
{ _id: "id1", metadata: { data: ["somedata1"], link: [] } },
{ _id: "id2", metadata: { data: ["somedata2"], link: ["id2", "id3"] } },
{ _id: "id3", metadata: { data: ["somedata3"], link: ["id2", "id3"] } },
{ _id: "id4", metadata: { data: ["somedata4"] } }
]
const result = data.reduce((acumD, d) => {
const link = d?.metadata?.link;
if (!link) {
if (acumD['NONE']) {
acumD['NONE'].push(d)
} else {
acumD['NONE'] = [d];
}
} else if (link.length === 0) {
if (acumD['EMPTY']) {
acumD['EMPTY'].push(d)
} else {
acumD['EMPTY'] = [d];
}
} else {
const linkString = link.join(',');
if (acumD[linkString]) {
acumD[linkString].push(d)
} else {
acumD[linkString] = [d];
}
}
return acumD;
}, {});
console.log('result', Object.values(result));
Here's a generic grouping function:
function groupBy(a, fn) {
let m = new Map
for (let x of a) {
let key = fn(x)
if (!m.has(key))
m.set(key, [])
m.get(key).push(x)
}
return [...m.values()]
}
Applied to the problem at hand:
result = groupBy(
data,
x => JSON.stringify(x.metadata.link))
produces the desired result.

How to update deeply nested array of objects?

I have the following nested array of objects:
const data = [
{
product: {
id: "U2NlbmFyaW9Qcm9swkdWN0OjEsz",
currentValue: 34300,
},
task: {
id: "R2VuZXJpY1Byb2R1Y3Q6MTA",
name: "My Annuity",
},
instrumentDetails: [
{
instrument: {
id: "U2NlbmFyaW9JbnN0cnVtZW50OjEz",
supplier: {
id: "U3VwcGxpZXJJbnN0cnVtZW50OjUzNjQ",
supplierDetails: {
name: "Local - Class A",
},
},
currentValue: 44323,
},
assets: {
current: 1.2999270432626702,
fixed: 0.5144729302004819,
financial: 0.0723506386331588,
cash: 0.00006003594786398524,
alternative: 0.05214078143244779,
property: 0.548494862567579,
local: 0.10089348539739094,
global: 0,
},
},
],
},
{
product: {
id: "U2NlbmFyaW9Qcm9swkfefewdWN0OjEsz",
currentValue: 3435300,
},
task: {
id: "R2VuZXJpYfewfew1Byb2R1Y3Q6MTA",
name: "Living",
},
instrumentDetails: [
{
instrument: {
id: "U2NlbmFyadewwW9JbnN0cnVtZW50OjEz",
supplier: {
id: "U3VwcGxpZdwdwXJJbnN0cnVtZW50OjUzNjQ",
supplierDetails: {
name: "Local - Class B",
},
},
currentValue: 434323,
},
assets: {
current: 1.294353242,
fixed: 0.514434242004819,
financial: 0.07434286331588,
cash: 0.0000434398524,
alternative: 0.05242348143244779,
property: 0.543242567579,
local: 0.100432439739094,
global: 0,
},
},
],
},
];
The above data presents an array of products which consist of instruments that are described in instrumentDetails array. I am trying to find an instrument by supplier id and update its assets by multiplying all of the asset values by a given number.
Here is my function:
export const updateObject = (
productsArr: any,
supplierInstrumentId: string
) => {
return productsArr.map(
(product: any) => {
product.instrumentDetails.map(
(instrumentDetail: any) => {
if (
instrumentDetail.instrument.supplier.id ===
supplierInstrumentId
) {
instrumentDetail.assets.current = instrumentDetail.assets.current + 5;
instrumentDetail.assets.fixed= instrumentDetail.assets.fixed+ 5;
instrumentDetail.assets.financial= instrumentDetail.assets.financial+ 5;
instrumentDetail.assets.cash= instrumentDetail.assets.cash+ 5;
}
}
);
}
);
};
This function is giving an error :
Uncaught TypeError: Cannot assign to read only property 'current' of
object '#'
How can I deeply update the above data? Please help.
You need to return a new instrumentDetail-type object from the map function. Don't try to update the existing object.
(instrumentDetail: any) => {
const assets = instrumentDetail.instrument.supplier.id === supplierInstrumentId
? Object.fromEntries(
Object.entries(instrumentDetail.assets).map(([k, v]) => [k, v + 5])
)
:
instrumentDetail.assets;
return {
...instrumentDetail,
assets
};
}
Your product map is not returning which is why you're likely getting an undefined. I wasn't getting the typescript error which you mentioned above. This should leave the array in the state at which you intended.
const updateObject = (
productsArr: any,
supplierInstrumentId: string
) => {
return productsArr.map(
(product: any) => {
product.instrumentDetails.map(
(instrumentDetail: any) => {
if (
instrumentDetail.instrument.supplier.id ===
supplierInstrumentId
) {
instrumentDetail.assets.current += 5;
instrumentDetail.assets.fixed= instrumentDetail.assets.fixed+ 5;
instrumentDetail.assets.financial= instrumentDetail.assets.financial+ 5;
instrumentDetail.assets.cash= instrumentDetail.assets.cash+ 5;
return instrumentDetail;
}
}
);
return product;
}
);
};

JS: append array of objects with data from another

I've got some JS data holding all kinds of data, numbers, child objects, arrays, etc in all manner of different structures:
let datapile = {
cover_img: { uid:'u2a3j4' },
avatar_img: { uid:'u5j3vg' },
created: 8273736384,
friends: [
{ name:'John', img: { uid:'u2726b' }, },
{ name:'Jane', parent: { profile_img: { uid:'u293k4' }, } },
],
occupation: {
past: current,
prior: {
title: 'Accountant',
company: {
logo: { img: { uid:'u29374' } },
}
},
},
...
}
And then I've got this JS list of images:
let imgs : [
{ uid:'u2a3j4', format:'jpg', alt_txt:'Lorem...', size:583729, dominant_color:'#d79273' },
{ uid:'u5j3vg', format:'png', alt_txt:'Lorem...', size:284849, dominant_color:'#f99383' },
{ uid:'u2726b', format:'gif', alt_txt:'Lorem...', size:293742, dominant_color:'#349a83' },
...
],
Now, what I need is a function I can call that will look through the datapile and append img data objects from the imgs list below. So where the datapile now has only the uid reference, it should have the entire img object. And I will then do the same with all kinds of other pieces of referenced data.
I've tried the following function:
function isArray(x){ return ( x !== undefined && Array.isArray(x) ) }
function isObject(x){ return (x && typeof x === "object" && !Array.isArray(x)) }
function get_item(type, uid) { /* loops through eg. imgs and returns img matching uid */ }
function append_referenced_relations(data){
if( !data ) return data
if( isObject(data) && data['uid'] !== undefined ) {
let item = get_item('any', data['uid'])
data = item
}
if( isObject(data) || isArray(data) ) {
for( let key in data ) {
data[key] = this.append_referenced_relations(deepClone(data[key]))
}
}
return data
}
... but I just can't get it to work. And my best googling efforts for similar scenarios have also come up empty. Can the internet help me out here?
you can try something like this
basically it use recursion and Object.fromEntries /entries to check all the keys of the inner object
if you have any specific question feel free to ask me
const decorate = (obj, data) => {
if (typeof obj !== 'object') {
return obj
}
if (Array.isArray(obj)) {
return obj.map(e => decorate(e, data))
}
return Object.fromEntries(
Object.entries(obj).flatMap(([k, v]) => {
if (k === 'uid') {
const imgData = data.find(d => v === d.uid)
return Object.entries(imgData || [[k, v]])
}
return [
[k, decorate(v, data)]
]
})
)
}
let datapile = {
cover_img: {
uid: 'u2a3j4'
},
avatar_img: {
uid: 'u5j3vg'
},
created: 8273736384,
friends: [{
name: 'John',
img: {
uid: 'u2726b'
},
},
{
name: 'Jane',
parent: {
profile_img: {
uid: 'u293k4'
},
}
},
],
occupation: {
past: 'current',
prior: {
title: 'Accountant',
company: {
logo: {
img: {
uid: 'u29374'
}
}
}
}
}
}
let imgs = [{
uid: 'u2a3j4',
format: 'jpg',
alt_txt: 'Lorem...',
size: 583729,
dominant_color: '#d79273'
},
{
uid: 'u5j3vg',
format: 'png',
alt_txt: 'Lorem...',
size: 284849,
dominant_color: '#f99383'
},
{
uid: 'u2726b',
format: 'gif',
alt_txt: 'Lorem...',
size: 293742,
dominant_color: '#349a83'
}
]
console.log(decorate(datapile, imgs))
You need to recurse in the nested datapile to identify the object with uids and add the img properties to be added.
Few cases to consider:
Objects. (If the Object has uid property, then stop recursion for its properties)
Object values having objects.
Array of Objects.
No need to return anywhere in your function actually as we can update objects inline.
Try like below.
let imgs = [ { uid: "u2a3j4", format: "jpg", alt_txt: "Lorem...", size: 583729, dominant_color: "#d79273", }, { uid: "u5j3vg", format: "png", alt_txt: "Lorem...", size: 284849, dominant_color: "#f99383", }, { uid: "u2726b", format: "gif", alt_txt: "Lorem...", size: 293742, dominant_color: "#349a83", }, { uid: "u293k4", format: "gif", alt_txt: "Lorem...", size: 193742, dominant_color: "#349a83", }, { uid: "u29374", format: "gif", alt_txt: "Lorem...", size: 793742, dominant_color: "#349a83", }, ]; let datapile = { cover_img: { uid: "u2a3j4" }, avatar_img: { uid: "u5j3vg" }, created: 8273736384, friends: [ { name: "John", img: { uid: "u2726b" } }, { name: "Jane", parent: { profile_img: { uid: "u293k4" } } }, ], occupation: { past: "current", prior: { title: "Accountant", company: { logo: { img: { uid: "u29374" } }, }, }, }, };
function isArray(x) {
return x !== undefined && Array.isArray(x);
}
function isObject(x) {
return typeof x === "object" && !Array.isArray(x);
}
function get_item(uid) {
return imgs.find((img) => img.uid === uid);
}
function append_referenced_relations(data) {
if (isObject(data)) {
if (data["uid"] !== undefined) {
const img = get_item(data.uid);
// Add img properties to the same object as properties
Object.entries(img).forEach(([key, value]) => {
data[key] = value;
});
} else {
// Recurse for the object values
Object.values(data).forEach((item) => {
append_referenced_relations(item);
});
}
} else if (isArray(data)) {
data.forEach((item) => {
// Recurse for the array entries
append_referenced_relations(item);
});
}
}
append_referenced_relations(datapile);
console.log(JSON.stringify(datapile, null, 2));

Filter the data array by onChange an input value

In the code below, I am trying to run onChange={this.handleChange} with react js.I would like to obtain the items by filtering them based on what is written on Input,I tried the following :
<input value={this.state.name} onChange={this.handleChange}/>
handleChange= evt =>
this.setState(
{
name: evt.target.value.toLowerCase()
},
() => {
.
.
.
}
)
Firstly there is an input and the its function that return the value of the input.
const data=[
{ "info": [{ "name": "ali" }, { "name": "amir" }, { "name": "maya" }] },
{ "info": [{ "name": "eli" }, { "name": "mary" }] },
{ "info": [{ "name": "ali" }] },
{
"info": [{ "name": "emila" }, { "name": "alex" }, { "name": "sosan" }]
}
]
data = data .filter(item => {
if (this.renderName(item).some((r) => {
r.includes(name)
}
)) return item;
})
renderName(element){
let elementAdd = []
for (let i = 1; i < element.info.length; i++) {
elementAdd.push(element.info[i].name.toLowerCase())
}
return elementAdd
}
And I want to filter the data array based on input value, but it does not work!
Edit:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
{ id: 1, info: [{ name: "ali" }, { name: "amir" }, { name: "maya" }] },
{ id: 2, info: [{ name: "eli" }, { name: "mary" }] },
{ id: 3, info: [{ name: "mary" }] },
{
id: 4,
info: [{ name: "emila" }, { name: "alex" }, { name: "sosan" }],
},
],
name: "",
};
}
reorganiseLibrary = () => {
const { name } = this.state;
let library = data;
if (name !== "") {
library = library.filter((item) => {
if (
this.renderName(item).some((r) => {
name.includes(r);
})
)
return item;
});
}
};
renderName(element) {
let elementAdd = [];
for (let i = 1; i < element.info.length; i++) {
elementAdd.push(element.info[i].name.toLowerCase());
}
return elementAdd;
}
handleChange = (evt) =>
this.setState(
{
name: evt.target.value.toLowerCase(),
},
() => {
this.reorganiseLibrary();
}
);
renderLibrary = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.map((item) => <div className="item">{item.id}</div>);
};
render() {
return (
<div>
<input value={this.state.name} onChange={this.handleChange} />
{this.renderLibrary()}
</div>
);
}
}
ReactDOM.render(<App></App>, document.getElementById("app"));
There are many issues in your code and I will only discuss the critical points.
reorganiseLibrary method
data not extracted from props
handleChange method
wrong use of setState. No second parameter as far as I know.
renderName method
you only get name property but you expect an object in renderLibrary method
Here is a solution that I can think of.
state = {
data: [],
name: "",
library: [] // use this to show latest filtered data
}
function onChange(event) {
const { data} = this.state;
this.setState(
{
name: event.target.value.toLowerCase()
});
let filteredResult = [];
for(var index = 0; index < data.length; index++) {
var filteredValue = data[index].info.filter(item => item.name.includes(event.target.value));
if(filteredValue.length != 0)
filteredResult.push(filteredValue);
}
if(filteredResult.length != 0) // remove this if you want to reset the display in your UI
setState({library : filteredResult});
}
renderLibrary = () => {
const { library } = this.state;
if (library.length > 0)) {
return library.foreach(item => (<div className="item">{item.id}</div>)); // modify the onChange filter if you want the outer object
};

The value of the checkbox is added to the array but the checkbox is not checked

I have checked two checkboxes. I can unchecked them, but i can't again checked them. When unchecked checkboxes, the value is removed from the array peopleChecked, when them wants to mark the value is added to the array peopleChecked, but the checkboxes aren't checked
Code here:
class App extends Component {
constructor() {
super();
this.state = {
people: [
{
firstname: "Paul",
userCompetences: [
{
asset: {
id: "12345"
}
}
]
},
{
firstname: "Victor",
userCompetences: [
{
asset: {
id: "5646535"
}
}
]
},
{
firstname: "Martin",
userCompetences: [
{
asset: {
id: "097867575675"
}
}
]
},
{
firstname: "Gregor",
userCompetences: [
{
asset: {
id: "67890"
}
}
]
}
],
peopleChecked: [
{
amount: 0,
asset: {
id: "fgfgfgfg",
name: 'Gregor'
},
asset_id: '67890'
},
{
amount: 0,
asset: {
id: "dsdsdsd"
},
asset_id: '12345'
},
],
selectPeopleId: []
}
}
handleSelect = (person) => {
//Check if clicked checkbox is already selected
var found = this.state.peopleChecked.find((element) => {
return element.asset_id === person.userCompetences[0]['asset']['id'];
});
console.log(found);
if(found){
//If clicked checkbox already selected then remove that from peopleChecked array
this.setState({
peopleChecked: this.state.peopleChecked.filter(element => element.asset_id !== person.userCompetences[0]['asset']['id']),
selectPeopleId: this.state.selectPeopleId.filter(element => element !== person.userCompetences[0]['asset']['id'])
}, () => console.log(this.state.peopleChecked))
}else{
//If clicked checkbox is not already selected then add that in peopleChecked array
this.setState({
selectPeopleId: [...this.state.selectPeopleId, person.userCompetences[0]['asset']['id']],
peopleChecked: [...this.state.peopleChecked, person]
}, () => {console.log(this.state.selectPeopleId)})
}
}
render() {
return (
<div>
{this.state.people.map(person => (
<div key={person.firstname} className="mb-1">
<input
type={'checkbox'}
id={person.id}
label={person.firstname}
checked={
this.state.peopleChecked.some(
({ asset_id }) => asset_id === person.userCompetences[0]['asset']['id']
)}
onChange={() => this.handleSelect(person)}
/> {person.firstname}
</div>
))}
</div>
);
}
}
You can probably simplify your handleSelect logic a bit. Try breaking it down so you have an array of strings to work with. This is all you need just to toggle the checkboxes:
See sandbox with working code: https://stackblitz.com/edit/react-xsqhwt?file=index.js
handleSelect = person => {
const { peopleChecked } = this.state;
let peopleCheckedClone = JSON.parse(JSON.stringify(peopleChecked));
const personId = person.userCompetences[0].asset.id;
const removeIndex = peopleChecked.findIndex(
person => person.asset_id === personId
);
if (removeIndex >= 0) {
peopleCheckedClone.splice(removeIndex, 1);
} else {
peopleCheckedClone = [...peopleCheckedClone, { asset_id: personId }];
}
this.setState({
peopleChecked: peopleCheckedClone
});
};

Categories

Resources