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": "[email protected]"
    },
    "comment": "my comment 0",
    "done": true
}
...
]

$scope.users

[
{
    "id": 34,
    "name": "User 1",
    "email": "[email protected]"
},
{
    "id": 35,
    "name": "User 2",
    "email": "[email protected]"
},
{
    "id": 36,
    "name": "User 3",
    "email": "[email protected]"
}
]

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>
3
  • 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" Commented Feb 10, 2014 at 16:08
  • You have todo on your ng-model and ng-show but todos on your scope. Commented Feb 10, 2014 at 16:50
  • I've added the structure as requested. Also provided more information why todo is in my scope. Commented Feb 11, 2014 at 12:39

2 Answers 2

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": "[email protected]"} */

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": "[email protected]"
} // like this

todo.assignee // now change the whole value
/* {"id": 36,
    "name": "User 3",
    "email": "[email protected]"} */
Sign up to request clarification or add additional context in comments.

5 Comments

This does not solve the problem. I tried it. I also added {{ todo.assignee.name }} after the select. It properly shows the name.
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.
Update again my answer~
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.
I add some explanation. Don't be afraid. It's not terrible, and it's common solution. you can refer this: stackoverflow.com/questions/18647098/…
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

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.