goatslacker / goatslacker/alt

Nested / complex data structure

Open
#435 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
3.4k
Forks
312
PR merge metrics
No merged PRs in 30d

Description

Not specifically to Alt, though. **I am not sure how to structure my stores with this certain situation.**

---

Let's say, we have 3 resources: `Member`, `Group`, and `Conversation`.

`Member` _belongsToMany_ `Conversation`; and vice-versa. (x:x)
`Member` _belongsTo_ `Group` (x:1)

`Group` and `Conversation` has no direct relationship. This is because `Group` is only being used to literally contain a `Member`.

* Note that the API route (`api/groups/` -- which is expected to return all groups also includes its contacts) . It returns something like this:

``` js
{
"id": 1,
// ....
"members": [
{
"id": 4,
// ...
}
]
}
```

---

This is the UI:

![screenshot 2015-08-03 13 56 36](https://cloud.githubusercontent.com/assets/5093058/9031582/75370a1e-39e7-11e5-81b9-7ac8ec3cd6b6.png)

This is for creating a Message. A message requires contacts (ids) and a few fields. The Group checkbox is simply used to select all contacts under it. It does not have anything to do with the Message itself.

---

Currently, I just have a `GroupStore` and `SelectedContactStore`. However, I feel that the current setup is a bit tedious, and very prone to errors. I am not sure if this is due to _Immutable_.

Here's an idea of the code:

``` es6
// SelectedMemberStore
import { createStore } from 'alt/utils/decorators';
import Immutable from 'immutable';
import immutable from 'alt/utils/ImmutableUtil';

import alt from '../alt';
import MemberActions from '../actions/MemberActions';
import GroupStore from '../actions/GroupStore';

@createStore(alt)
@immutable
class SelectedMemberstore {
state = {
selected: Immutable.List()
};

constructor() {
this.bindListeners({
// onFetchAll: onFetchAll,
onSelectMember: MemberActions.SELECT_MEMBER,
onSelectGroup: MemberActions.SELECT_GROUP
});

this.exportPublicMethods({
getIndexById: ::this.getIndexById,
isMemberSelected: ::this.isMemberSelected,
isGroupSelected: ::this.isGroupSelected
});
}

isGroupSelected(groupId) {
const group = GroupStore.getById(groupId);
const { selected } = this.state;
const members = group.get('members');

return !members.size ? false : members
.filter(member => selected.indexOf(member.get('id')) !== -1)
.size === members.size;
}

isMemberSelected(id) {
return this.getIndexById(id) !== -1;
}

getIndexById(id) {
return this.state.selected.indexOf(id);
}

onSelectMember(id) {
this.setState({
selected: this.state.selected.push(id)
});
}

onSelectGroup(groupId) {
const group = GroupStore.getById(groupId);
const members = group.get('members');
const { selected } = this.state;

this.setState({
selected: !this.isGroupSelected(group) ? selected.concat(
members.filter(member => (
selected.indexOf(member.get('id')) === -1
)).map(member => member.get('id'))
) : selected.filter(id => (
members.map(member => member.get('id')).indexOf(id) === -1
))
});
}
}

export default SelectedMemberstore;
```

Any better way to do this?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.