0

Preselection is not working in the select field even though the objects are equal:

<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee" 
        ng-model="todo.assignee" required 
        ng-options="user.name for user in users">
</select>

todo.assignee contains a user object, which should match one from users.

It seems that Angular does not recognize that the User object from todo.assignee is contained in users. Can I perform this mapping manually?

The select is shown with no value selected. I can choose a user (from users) and save the record without any problem.

Controller

$scope.todos = Todo.query();
$scope.users = User.query();

Update

As requested in the comments. Structure of the given objects: $scope.todos

 [
{
    "id": 157,
    "description": "my description 0",
    "deadline": 1392073200000,
    "assignee": {
        "id": 34,
        "name": "User 1",
        "email": "user1@hotmail.com"
    },
    "comment": "my comment 0",
    "done": true
}
...
]

$scope.users

[
{
    "id": 34,
    "name": "User 1",
    "email": "user1@hotmail.com"
},
{
    "id": 35,
    "name": "User 2",
    "email": "xxc@gmail.com"
},
{
    "id": 36,
    "name": "User 3",
    "email": "xx@hotmail.com"
}
]

The scope of the select comes from a repeat:

<tr ng-repeat="todo in todos | filter:query | filter:{assignee:queryAssignee} | filter:queryDone" ng-class="{danger: isDue(todo)}">
                    <td>
Daniel
  • 834
  • 1
  • 9
  • 25
  • Could you add the structure of `users` and `todos`? If `todo.assignee` contains user object, you can use something like: `ng-model="todo.assignee.user.name"` – kubuntu Feb 10 '14 at 16:08
  • You have todo on your ng-model and ng-show but todos on your scope. – snaplemouton Feb 10 '14 at 16:50
  • I've added the structure as requested. Also provided more information why todo is in my scope. – Daniel Feb 11 '14 at 12:39

2 Answers2

5

According to your description:

todo.assignee contains a user object

But your options' value are user.name strings, one object and one string will never be matched.

So, replace

ng-model="todo.assignee"

to

ng-model="todo.assignee.name"

UPDATE:

use ng-options="user.name as user.name for user in users"

Full Answer:

<select ng-show="isEditMode(todo.id)" 
    ng-model="todo.assignee.name" required 
    ng-options="user.name as user.name for user in users">
</select>

Plnkr: http://plnkr.co/edit/A1XdMYmACNCr3OwBuFhk?p=preview

select as label for value in array

label: The result of this expression will be the label for element. The expression will most likely refer to the value variable (e.g. value.propertyName).

you can have refer here: http://docs.angularjs.org/api/ng.directive:select

UPDATE2:

To fix the side effect, you can use option with separated value and display name

<select ng-model="todo.assignee" required>
    <option ng-repeat="user in users" value="{{user}}" ng-selected="todo.assignee.name === user.name">
        {{user.name}}
    </option>
</select>

Plnkr: http://plnkr.co/edit/6tzP9ZexnYUUfwAgti9b?p=preview

Explanation:

Before:

When you select one of option, it assign option value to model todo.assignee.name, so only change the name.

todo.assignee.name = "User 3" // like this

todo.assignee // didn't change the id & email
/* {"id": 34,
    "name": "User 1",
    "email": "user1@hotmail.com"} */

But, Now:

When you select one of option, it assign object value to model todo.assignee, so let what you want.

todo.assignee.name = { 
    "id": 36,
    "name": "User 3",
    "email": "user3@hotmail.com"
} // like this

todo.assignee // now change the whole value
/* {"id": 36,
    "name": "User 3",
    "email": "user3@hotmail.com"} */
Chen-Tsu Lin
  • 22,876
  • 16
  • 53
  • 63
  • This does not solve the problem. I tried it. I also added {{ todo.assignee.name }} after the select. It properly shows the name. – Daniel Feb 11 '14 at 12:31
  • Thanks a lot for your help. The pre selection works now. It has an side effect though. It will create invalid objects. I expected that the complete user object in todo.assignee will be changed but only the name will be changed like this. So I will need to fix this in the background (setting correct object based on the name), which is a bit ugly. – Daniel Feb 11 '14 at 15:50
  • Update again my answer~ – Chen-Tsu Lin Feb 11 '14 at 16:12
  • I'm afraid, this causes another problem. Value is now a string and not an object anymore. So I prefer the workaround with post processing the selection. I thought my scenario should not be that seldom, so I'm surprised angular can't handle this. – Daniel Feb 11 '14 at 19:16
  • I add some explanation. Don't be afraid. It's not terrible, and it's common solution. you can refer this: http://stackoverflow.com/questions/18647098/initializing-select-with-angularjs-and-ng-repeat – Chen-Tsu Lin Feb 12 '14 at 02:32
2

Maybe it can be useful for someone else:

<select ng-show="isEditMode(todo.id)" id="assignee" name="assignee" 
        ng-model="todo.assignee" required 
        ng-options="user as user.name for user in users track by user.id">
</select>

The magic trick is in "track by user.id"

https://docs.angularjs.org/api/ng/directive/ngOptions

krusk8
  • 71
  • 2
  • 9
  • This works for me! It's important to note, that the model, must be a reference to the object, and not a reference to the todo.assignee.id. – MMM Nov 07 '18 at 07:56