IchBinGrumpig
IchBinGrumpig

Reputation: 139

How to observe an array inside an array with Aurelia?

I have a people array of objects where each Object (representing a person) contains a roles array:

@observable people = [
  {
    name: 'Name1',
    roles: [
      '1',
      '2'
    ]
  },
  {
    name: 'Name2',
    roles: [
      '3',
      '4'
    ]
  }
]

I want the view to iterate through and show them (e.g. repeat.for="role of roles"). The view does not get updated, however, when the people array updated. Example code where the Angular-option is the one not working for me:

<select name="roles" multiple class="ui fluid multiple dropdown">
  <option value="">Roles</option>
  <option selected.bind="accounts[2].roles.includes('1')" value="angular">Angular</option>
  <option value="css">CSS</option>
  <option value="design">Graphic Design</option>
  <option value="ember">Ember</option>
</select>

When I initialize the people array to contain the third person with a role '1' from the beginning everything works just fine, but when I dynamically add the same third person (e.g. via button) it is not updated.

I know how to observe the people array with collectionObservers via

this.subscription = this.bindingEngine.collectionObserver(this.people)
  .subscribe(this.peopleChanged.bind(this))

but I am not interested in the whole this.people array but in the nested array roles array inside this.people. How can I address this problem of observing arrays inside arrays with obersers?

Upvotes: 1

Views: 397

Answers (1)

Collin Herber
Collin Herber

Reputation: 143

Something I don't recommend, however it is possible by simply just iterating through and binding individually. There isn't a top-level binding function, that I'm aware of anyway, that allows you bind on an array's nested array.

Something like this

(This is watching a specific property inside the roles array - Can easily change this to use the collectionObserver for each of the roles.)

 bindNestedArrayItems() {
        for (const person of people) {
            for (const role of person.roles) {
                this.bindingEngine
                    .propertyObserver(property, 'property')
                    .subscribe(() => this.peopleChanged(this));
            }
        }
 }

I would suggest however maybe creating a subscriber event for wherever this is being updated from. Perhaps you a webhook that listens if a role is changed? Wherever your listening/changing you can do this.eventAggregator.publish('role-updated', {user: user}) and then have a this.eventAggregator.subscribe('role-updated', (data) => { if (data.user) { let userThatUpdated = this.person.find(x => x.Id === data.user.id)} or something.

This way you know something happened and you don't have a hundred property/collection observers going.

Upvotes: 1

Related Questions