There is a unique scenario where two objects share data, yet have different structures.
For instance, the 'Team' object has the team ID as its key. The 'Team' object includes 'name' and 'users' objects as its values. The 'users' object utilizes user IDs exclusive to each team.
I need to create a new object that consolidates all users from different teams.
The 'users' object should be subscribable by users, with changes reflecting in the 'Team' object as well. Similarly, the 'Team' object should be subscribable by users, with modifications propagating to the 'users' object.
How can I accomplish this task?
I tried updating both objects using a 'subscribe' function in JavaScript files, but encountered an infinite loop and failure.
Below is the example code along with REPL.
<script>
import {writable} from "svelte/store";
const teamDict = writable({})
const userDict = writable({})
function initTeamDict() {
teamDict.set({
1: {
name: "good team",
users: {
1: "James",
2: "Poppy",
48: "Hway"
}
},
2: {
name: "bad team",
users: {
47: "Kelin",
35: "Teo",
24: "Ferma"
}
}
})
}
function initUserDict() {
userDict.set(Object.values($teamDict).reduce((acc, team) => ({...acc, ...team[`users`]}), {}))
}
</script>
<button on:click={initTeamDict}>init team dict</button>
<button on:click={initUserDict}>init user dict</button>
<div> {JSON.stringify($teamDict)}</div>
<div> {JSON.stringify($userDict)}</div>
<button on:click={() => $teamDict[`1`][`users`][`1`] = "top"}>this button should change userDict also </button>
<button on:click={() => $userDict[`1`] = "bottom"}>this button should change teamDict also </button>
REPL
Edit
By following @ghostmodd's solution, I resolved the issue with the provided code below.
Since modifying a copied object does not trigger a subscription, I duplicated the object before making changes.
In order to manage the modified object rendering order, I implemented a separate view using derived.
<script>
import {derived, writable} from "svelte/store";
import {Button} from "flowbite-svelte";
const teamDict = writable({})
const userDict = writable({})
teamDict.subscribe(($$teamDict) => {
const userDictCopy = $userDict
for (const key in userDictCopy) {
delete userDictCopy[key]
}
Object.assign(userDictCopy, Object.values($$teamDict).reduce((acc, team) => ({...acc, ...team[`users`]}), {}))
})
userDict.subscribe(($$userDict) => {
const teamDictCopy = $teamDict
for (const team of Object.values(teamDictCopy)) {
team[`users`] = {}
}
for (const [userId, user] of Object.entries($$userDict)) {
teamDictCopy[user[`team_id`]][`users`][userId] = user
}
})
const storeView = derived(
[teamDict, userDict],
([$teamDict, $userDict], set) => {
set({teamDict: $teamDict, userDict: $userDict})
}
)
function initTeamDict() {
teamDict.set({
1: {
name: "good team",
users: {
1: {
"name": "James",
"team_id": 1
},
2: {
"name": "Poppy",
"team_id": 1
},
48: {
"name": "Hway",
"team_id": 1
}
}
},
2: {
name: "bad team",
users: {
47: {
"name": "Kelin",
"team_id": 2
},
35: {
"name": "Teo",
"team_id": 2
},
24: {
"name": "Ferma",
"team_id": 2
}
}
}
})
}
</script>
<Button on:click={initTeamDict}>init team dict</Button>
<div> {JSON.stringify($storeView.teamDict)}</div>
<div> {JSON.stringify($storeView.userDict)}</div>
<Button on:click={() => $teamDict[`1`][`users`][`1`][`name`] = "top"}>this button should change userDict also </Button>
<Button on:click={() => $userDict[`1`][`name`] = "bottom"}>this button should change teamDict also </Button>
REPL