Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding a select to an array of objects in Aurelia and matching on ID

So, I have a list of all users, which populates the options of a select.

<option repeat.for="user of userService.users">
  ${user.firstName} ${user.lastName}
</option>

And I have an incoming group record which has a list of users attached to it. I follow the cheat sheat instructions and bind it to a single index of the model.

<select value.bind="group.users[0]">
    <option repeat.for="user of userService.users" model.bind="user">
      ${user.firstName} ${user.lastName}
    </option>
</select>

So, the incoming user in the group is identical to one of the users in the list:

{
    id: 123,
    firstName: 'Matt',
    lastName: 'Davis'
}

But when the group is loaded and bound to the view, the correct user is not chosen from the select. Actually, I would expect this as JavaScript would look for referential equality.

Ideally, I'd like Aurelia to find that the incoming record is as above and (a) search through the list of options testing equality (b) that I've defined in some extension (maybe a filter?), (c) select it in the list and (d) propagate that selection back into the record so that the record is now referentially in sync.

I would rather not fall back to a trigger that manually does this because I will have lots and lots of these kinds of selects throughout my application.

I would settle, albeit sadly, for (a) and (c).

like image 895
Matthew James Davis Avatar asked Nov 25 '15 15:11

Matthew James Davis


1 Answers

Specify a matcher function (equality comparer):

<select value.bind="group.users[0]" matcher.bind="userComparer">
  <option repeat.for="user of userService.users" model.bind="user">
    ${user.firstName} ${user.lastName}
  </option>
</select>
export class Foo {
  ...
  userComparer = (userA, userB) => userA.id === userB.id;
  ...
}

Below is the original answer (before 11/30/2015 release)...

Until this is supported natively by aurelia's select binding I would try something like this:

<select value.bind="group.users[0] | userToId:userService.users">
  <option repeat.for="user of userService.users" model.bind="user.id">
    ${user.firstName} ${user.lastName}
  </option>
</select>
export class UserToIdValueConverter {
  toView(user, users) {
    return user ? user.id : null;
  }

  fromView(id, users) {
    return users.find(u => u.id === id);
  }
}

Here's a plunker: http://plnkr.co/edit/15XHkQ?p=preview

You'll probably want to make the converter generic so you can reuse it throughout your app... maybe something like this:

export class ToIdValueConverter {
  toView(obj, idPropertyName, objs) {
    return obj ? obj[idPropertyName] : null;
  }

  fromView(id, idPropertyName, objs) {
    return objs.find(o => o[idPropertyName] === id);
  }
}
<select value.bind="group.users[0] | toId:'id':userService.users">
  <option repeat.for="user of userService.users" model.bind="user.id">
    ${user.firstName} ${user.lastName}
  </option>
</select>

Keep an eye on this issue for updates on native framework support for this scenario.

like image 77
Jeremy Danyow Avatar answered Nov 01 '22 21:11

Jeremy Danyow