320
votes

Given the following select element

<select ng-options="size.code as size.name for size in sizes " 
        ng-model="item.size.code" 
        ng-change="update(MAGIC_THING)">
</select>

Is there a way to get MAGIC_THING to be equal to the currently selected size, so I have access to size.name and size.code in my controller?

size.code affects a lot of the other parts of the app (image urls, etc), but when the ng-model of item.size.code is updated, item.size.name needs to be updated as well for the user facing stuff. I assume that the correct way to do this is capturing the change event and setting the values inside of my controller, but I'm not sure what I can pass into update to get the proper values.

If this is completely the wrong way to go about it, I'd love to know the right way.

10

10 Answers

496
votes

Instead of setting the ng-model to item.size.code, how about setting it to size:

<select ng-options="size as size.name for size in sizes" 
   ng-model="item" ng-change="update()"></select>

Then in your update() method, $scope.item will be set to the currently selected item.

And whatever code needed item.size.code, can get that property via $scope.item.code.

Fiddle.

Update based on more info in comments:

Use some other $scope property for your select ng-model then:

<select ng-options="size as size.name for size in sizes" 
   ng-model="selectedItem" ng-change="update()"></select>

Controller:

$scope.update = function() {
   $scope.item.size.code = $scope.selectedItem.code
   // use $scope.selectedItem.code and $scope.selectedItem.name here
   // for other stuff ...
}
51
votes

You can also directly get selected value using following code

 <select ng-options='t.name for t in templates'
                  ng-change='selectedTemplate(t.url)'></select>

script.js

 $scope.selectedTemplate = function(pTemplate) {
    //Your logic
    alert('Template Url is : '+pTemplate);
}
16
votes

you also coud try this:

<select  ng-model="selectedItem" ng-change="update()">
   <option ng-repeat="item in items" 
         ng-selected="selectedItem == item.Id" value="{{item.Id}}">
      {{item.Name}}
   </option>
</select>
8
votes

If Divyesh Rupawala's answer doesn't work (passing the current item as the parameter), then please see the onChanged() function in this Plunker. It's using this:

http://plnkr.co/edit/B5TDQJ

2
votes
<select ng-model="item.size.code">
<option ng-repeat="size in sizes" ng-attr-value="size.code">{{size.name}}          </option>
</select>
2
votes

//Javascript
$scope.update = function () {
    $scope.myItem;
    alert('Hello');
}
<!--HTML-->
<div class="form-group">
     <select name="name"
             id="id" 
             ng-model="myItem" 
             ng-options="size as size.name for size in sizes"
             class="form-control" 
             ng-change="update()"
             multiple
             required>
     </select>
</div>

İf you want to write, name, id, class, multiple, required , You can write in this way.

1
votes

This might give you some ideas

.NET C# View Model

public class DepartmentViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

.NET C# Web Api Controller

public class DepartmentController : BaseApiController
{
    [HttpGet]
    public HttpResponseMessage Get()
    {
        var sms = Ctx.Departments;

        var vms = new List<DepartmentViewModel>();

        foreach (var sm in sms)
        {
            var vm = new DepartmentViewModel()
            {
                Id = sm.Id,
                Name = sm.DepartmentName
            };
            vms.Add(vm);
        }

        return Request.CreateResponse(HttpStatusCode.OK, vms);
    }

}

Angular Controller:

$http.get('/api/department').then(
    function (response) {
        $scope.departments = response.data;
    },
    function (response) {
        toaster.pop('error', "Error", "An unexpected error occurred.");
    }
);

$http.get('/api/getTravelerInformation', { params: { id: $routeParams.userKey } }).then(
   function (response) {
       $scope.request = response.data;
       $scope.travelerDepartment = underscoreService.findWhere($scope.departments, { Id: $scope.request.TravelerDepartmentId });
   },
    function (response) {
        toaster.pop('error', "Error", "An unexpected error occurred.");
    }
);

Angular Template:

<div class="form-group">
    <label>Department</label>
    <div class="left-inner-addon">
        <i class="glyphicon glyphicon-hand-up"></i>
        <select ng-model="travelerDepartment"
                ng-options="department.Name for department in departments track by department.Id"
                ng-init="request.TravelerDepartmentId = travelerDepartment.Id"
                ng-change="request.TravelerDepartmentId = travelerDepartment.Id"
                class="form-control">
            <option value=""></option>
        </select>
    </div>
</div>
1
votes

You need to use "track by" so that the objects can be compared correctly. Otherwise Angular will use the native js way of comparing objects.

So your example code would change to -

    <select ng-options="size.code as size.name
 for size in sizes track by size.code" 
ng-model="item.size.code"></select>
1
votes

AngularJS's Filter worked out for me.

Assuming the code/id is unique, we can filter out that particular object with AngularJS's filter and work with the selected objects properties. Considering the example above:

<select ng-options="size.code as size.name for size in sizes" 
        ng-model="item.size.code" 
        ng-change="update(MAGIC_THING); search.code = item.size.code">
</select>

<!-- OUTSIDE THE SELECT BOX -->

<h1 ng-repeat="size in sizes | filter:search:true"
    ng-init="search.code = item.size.code">
  {{size.name}}
</h1>

Now, there are 3 important aspects to this:

  1. ng-init="search.code = item.size.code" - on initializing h1 element outside select box, set the filter query to the selected option.

  2. ng-change="update(MAGIC_THING); search.code = item.size.code" - when you change the select input, we'll run one more line which will set the "search" query to the currently selected item.size.code.

  3. filter:search:true - Pass true to filter to enable strict matching.

That's it. If the size.code is uniqueID, we'll have only one h1 element with the text of size.name.

I've tested this in my project and it works.

Good Luck

0
votes

This is the cleanest way to get a value from an angular select options list (other than The Id or Text). Assuming you have a Product Select like this on your page :

<select ng-model="data.ProductId"
        ng-options="product.Id as product.Name for product in productsList"
        ng-change="onSelectChange()">
</select>

Then in Your Controller set the callback function like so:

    $scope.onSelectChange = function () {
        var filteredData = $scope.productsList.filter(function (response) {
            return response.Id === $scope.data.ProductId;
        })
        console.log(filteredData[0].ProductColor);
    }

Simply Explained: Since the ng-change event does not recognize the option items in the select, we are using the ngModel to filter out the selected Item from the options list loaded in the controller.

Furthermore, since the event is fired before the ngModel is really updated, you might get undesirable results, So a better way would be to add a timeout :

        $scope.onSelectChange = function () {
            $timeout(function () {
            var filteredData = $scope.productsList.filter(function (response) {
                return response.Id === $scope.data.ProductId;
            })
            console.log(filteredData[0].ProductColor);
            }, 100);
        };