Работа с выбором с помощью AngularJS ng-options


442

Я читал об этом в других сообщениях, но я не мог понять это.

У меня есть массив,

$scope.items = [
   {ID: '000001', Title: 'Chicago'},
   {ID: '000002', Title: 'New York'},
   {ID: '000003', Title: 'Washington'},
];

Я хочу сделать это как:

<select>
  <option value="000001">Chicago</option>
  <option value="000002">New York</option>
  <option value="000003">Washington</option>
</select>

А также я хочу выбрать опцию с ID = 000002.

Я прочитал выбор и попытался, но я не могу понять это.


Я настоятельно рекомендую использовать Select2 , потому что он справится с этим для вас. Есть даже директива для AngularJS .
Хьюстон


На самом деле существует чистое решение AngularJS, разработанное QuantumUI . Вы можете найти больше примеров и документации на http://quantumui.org/ .
Рамон Дрюнс

Ответы:


799

Стоит отметить, что ngModel требуется для работы ngOptions ... обратите внимание на то, ng-model="blah"что говорится "установите $ scope.blah в выбранное значение".

Попробуй это:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

Вот еще из документации AngularJS (если вы ее еще не видели):

для источников данных массива:

  • метка для значения в массиве
  • выбрать в качестве метки для значения в массиве
  • метка группа по группе для значения в массиве = выбрать как метка группа по группе для значения в массиве

для источников данных объекта:

  • метка для (ключ, значение) в объекте
  • выбрать в качестве метки для (ключ, значение) в объекте
  • пометить группу за группой для (ключ, значение) в объекте
  • выбрать в качестве метки группу по группе для (ключ, значение) в объекте

Для пояснения значений тегов опций в AngularJS:

При использовании ng-options, значение опций тегов выписало нг-вариантами всегда будет индексом элемента массива дополнительный тег относится к . Это связано с тем, что AngularJS фактически позволяет вам выбирать целые объекты с элементами управления select, а не только примитивные типы. Например:

app.controller('MainCtrl', function($scope) {
   $scope.items = [
     { id: 1, name: 'foo' },
     { id: 2, name: 'bar' },
     { id: 3, name: 'blah' }
   ];
});
<div ng-controller="MainCtrl">
   <select ng-model="selectedItem" ng-options="item as item.name for item in items"></select>
   <pre>{{selectedItem | json}}</pre>
</div>

Вышеизложенное позволит вам выделить весь объект $scope.selectedItemнапрямую. Дело в том, что с AngularJS вам не нужно беспокоиться о том, что находится в вашем теге option. Пусть AngularJS справится с этим; Вы должны заботиться только о том, что находится в вашей модели в вашем объеме.

Вот плункер, демонстрирующий поведение выше и показывающий выписанный HTML


Работа с опцией по умолчанию:

Есть несколько вещей, которые я не упомянул выше, касающихся опции по умолчанию.

Выбор первого варианта и удаление пустого параметра:

Вы можете сделать это, добавив простое, ng-initкоторое устанавливает модель (from ng-model) для первого элемента в элементах, которые вы повторяете ng-options:

<select ng-init="foo = foo || items[0]" ng-model="foo" ng-options="item as item.name for item in items"></select>

Примечание: это может стать немного сумасшедшим, если fooслучится, что он правильно инициализирован для чего-то «ложного». В этом случае вы foo, скорее всего, захотите обработать инициализацию в вашем контроллере.

Настройка опции по умолчанию:

Это немного по-другому; здесь все, что вам нужно сделать, это добавить тег option как дочерний элемент вашего выбора с пустым атрибутом value, а затем настроить его внутренний текст:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="">Nothing selected</option>
</select>

Примечание. В этом случае «пустая» опция останется там даже после выбора другой опции. Это не относится к поведению по умолчанию выбора в AngularJS.

Настраиваемая опция по умолчанию, которая скрывается после выбора:

Если вы хотите, чтобы настроенная опция по умолчанию исчезла после выбора значения, вы можете добавить атрибут ng-hide к опции по умолчанию:

<select ng-model="foo" ng-options="item as item.name for item in items">
   <option value="" ng-if="foo">Select something to remove me.</option>
</select>

3
Оказывается, что это индексы значений, это то, как угловые могут позволить вам использовать объекты в качестве значения вашего поля выбора. Angular делает много вещей за кулисами с полями выбора, и вы не должны беспокоиться об атрибуте value в ваших опциях.
Бен Леш

1
Документация находится в разделе "выберите" на их сайте: docs.angularjs.org/api/ng.directive:select
Бен Леш,

25
«... ngModel требуется для работы ngOptions ...» - суть проблемы для меня. Хороший ответ.
Тристанм

1
Можно ли избежать первого пустого параметра ( <option value="?" selected="selected"></option>)?
Свендо

4
Я пытаюсь использовать последний случай ( настраиваемая опция по умолчанию, которая скрывается после выбора ), но я обнаружил некоторые проблемы. Вместо этого ng-if="foo"мне пришлось использовать, ng-if=!fooчтобы скрыть пустую опцию по умолчанию, когда выбрана другая опция. Кроме того, пустая опция по умолчанию появляется всегда внизу списка. Как я могу поставить его в начале списка?
Фрэн Эрреро

90

Я изучаю AngularJS и тоже боролся с отбором. Я знаю, что на этот вопрос уже дан ответ, но я все же хотел поделиться еще одним кодом.

В моем тесте у меня есть два списка: марки автомобилей и модели автомобилей. Список моделей отключен, пока не будет выбрана какая-либо марка. Если выбор в списке марок позднее сбрасывается (устанавливается «Выбрать марку»), тогда список моделей снова отключается и его выбор также сбрасывается (на «Выбор модели»). Марки извлекаются как ресурс, а модели просто жестко запрограммированы.

Делает JSON:

[
{"code": "0", "name": "Select Make"},
{"code": "1", "name": "Acura"},
{"code": "2", "name": "Audi"}
]

services.js:

angular.module('makeServices', ['ngResource']).
factory('Make', function($resource){
    return $resource('makes.json', {}, {
        query: {method:'GET', isArray:true}
    });
});

HTML-файл:

<div ng:controller="MakeModelCtrl">
  <div>Make</div>
  <select id="makeListBox"
      ng-model="make.selected"
      ng-options="make.code as make.name for make in makes"
      ng-change="makeChanged(make.selected)">
  </select>

  <div>Model</div>
  <select id="modelListBox"
     ng-disabled="makeNotSelected"
     ng-model="model.selected"
     ng-options="model.code as model.name for model in models">
  </select>
</div>

controllers.js:

function MakeModelCtrl($scope)
{
    $scope.makeNotSelected = true;
    $scope.make = {selected: "0"};
    $scope.makes = Make.query({}, function (makes) {
         $scope.make = {selected: makes[0].code};
    });

    $scope.makeChanged = function(selectedMakeCode) {
        $scope.makeNotSelected = !selectedMakeCode;
        if ($scope.makeNotSelected)
        {
            $scope.model = {selected: "0"};
        }
    };

    $scope.models = [
      {code:"0", name:"Select Model"},
      {code:"1", name:"Model1"},
      {code:"2", name:"Model2"}
    ];
    $scope.model = {selected: "0"};
}

27
Уважаемый случайный пользователь. Хотя этот вопрос и его ответ довольно просты и несложны, ваша организация кода в правильном и соответствующем месте (контроллер, служба, шаблон, данные) демонстрирует элегантность AngularJS в его простейшей форме и форме по умолчанию. Потрясающий пример.
Аттик

1
Это не так, как это должно быть использовано. ng-modelдолжен указывать на другую переменную в вашей области, не связанную с make. Смотрите пример в docs.angularjs.org/api/ng/directive/ngOptions
Дмитрий Зайцев

@DmitriZaitsev Я думаю, что вы не правы, просто потому, что пример угловых документов показывает то, что вы описали, не означает, что это единственный способ. Покажите нам, почему вы думаете, что он не должен использоваться таким образом, а не является отличным примером для новичков.
JRT

39

Почему-то AngularJS позволяет мне запутаться. Их документация довольно ужасна по этому поводу. Более хорошие примеры вариаций будут приветствоваться.

Во всяком случае, у меня есть небольшое отклонение от ответа Бена Леша.

Мои коллекции данных выглядят так:

items =
[
   { key:"AD",value:"Andorra" }
,  { key:"AI",value:"Anguilla" }
,  { key:"AO",value:"Angola" }
 ...etc..
]

Сейчас же

<select ng-model="countries" ng-options="item.key as item.value for item in items"></select>

по-прежнему приводит к тому, что значение опций будет индексом (0, 1, 2 и т. д.).

Добавление трека исправлено для меня:

<select ng-model="blah" ng-options="item.value for item in items track by item.key"></select>

Я считаю, что чаще всего вы хотите добавить массив объектов в список выбора, поэтому я запомню этот!

Имейте в виду, что из AngularJS 1.4 вы больше не можете использовать ng-options, но вам нужно использовать ng-repeatтег вашего option:

<select name="test">
   <option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>

3
Этот ответ кажется именно тем, о чем спрашивает вопрос. Каждый второй ответ говорит читателю не беспокоиться о том, что генерируется HTML, но если элемент select находится в форме, я очень волнуюсь. Отличный ответ!
Кит

3
Следует отметить, что в модели сохраняется весь выбранный объект, а не только ключ. Если вам нужен только ключ в модели, вы хотите использовать версию "item.key as item.value". Это немного смутило меня, так как я был зациклен на том, как выглядит HTML, а не на данных, которые я хотел получить в модели, что для меня является важной вещью.
mhenry1384

@ mhenry1384 Да, вы правы, об этом хранится весь объект. Мне действительно нравится эта функция, потому что она дает вам доступ не только к идентификатору (если он вам нужен). Хорошо работает для меня, когда я заполняю списки коллекцией Монго, и мне нужно какое-то свойство из выбранного элемента.
Mattijs

2
И как мы можем обнаружить изменения внутри «ng-change» option?
Константинос Натсиос

2
Что касается обновления, это выглядит не так. ng-options всё ещё отлично работает в 1.5. Это также все еще показано в документации. docs.angularjs.org/api/ng/directive/select
Джереми А. Вест

15

На этот вопрос уже дан ответ (кстати, действительно хороший и исчерпывающий ответ, предоставленный Беном), но я хотел бы добавить еще один элемент для полноты, который также может быть очень удобным.

В примере, предложенном Беном:

<select ng-model="blah" ng-options="item.ID as item.Title for item in items"></select>

была использована следующая форма ngOptions :select as label for value in array .

Метка - это выражение, результатом которого будет метка для <option>элемента. В этом случае вы можете выполнить определенные конкатенации строк, чтобы иметь более сложные метки опций.

Примеры:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" дает вам ярлыки, как Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items"дает вам метки, например Title (X), где Xдлина строки заголовка.

Вы также можете использовать фильтры, например,

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items"выдает метки вроде Title (TITLE), где значение Title свойства Title и TITLE - это то же значение, но преобразуется в заглавные буквы.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items"дает вам ярлыки, как Title (27 Sep 2015), если у вашей модели есть свойствоSomeDate

7

В CoffeeScript:

#directive
app.directive('select2', ->
    templateUrl: 'partials/select.html'
    restrict: 'E'
    transclude: 1
    replace: 1
    scope:
        options: '='
        model: '='
    link: (scope, el, atr)->
        el.bind 'change', ->
            console.log this.value
            scope.model = parseInt(this.value)
            console.log scope
            scope.$apply()
)
<!-- HTML partial -->
<select>
  <option ng-repeat='o in options'
          value='{{$index}}' ng-bind='o'></option>
</select>

<!-- HTML usage -->
<select2 options='mnuOffline' model='offlinePage.toggle' ></select2>

<!-- Conclusion -->
<p>Sometimes it's much easier to create your own directive...</p>

1
Не забудьте radixза parseInt: http://davidwalsh.name/parseint-radix
GFoley83

6

Если вам нужен пользовательский заголовок для каждого параметра, ng-optionsэто не применимо. Вместо этого используйте ng-repeatс параметрами:

<select ng-model="myVariable">
  <option ng-repeat="item in items"
          value="{{item.ID}}"
          title="Custom title: {{item.Title}} [{{item.ID}}]">
       {{item.Title}}
  </option>
</select>

3

Я надеюсь, что следующее будет работать для вас.

<select class="form-control"
        ng-model="selectedOption"
        ng-options="option.name + ' (' + (option.price | currency:'USD$') + ')' for option in options">
</select>

1

Это может быть полезно. Привязки не всегда работают.

<select id="product" class="form-control" name="product" required
        ng-model="issue.productId"
        ng-change="getProductVersions()"
        ng-options="p.id as p.shortName for p in products"></select>

Например, вы заполняете исходную модель списка опций из службы REST. Выбранное значение было известно до заполнения списка, и оно было установлено. После выполнения запроса REST с помощью $ http, опция list будет выполнена.

Но выбранная опция не установлена. По неизвестным причинам AngularJS в теневом $ digest при выполнении не привязывает выбранный, как должно быть. Я должен использовать JQuery, чтобы установить выбранное. Это важно! AngularJS в тени добавляет префикс к значению атрибута "значение" для сгенерированных опциями ng-repeat. Для int это "номер:".

$scope.issue.productId = productId;
function activate() {
    $http.get('/product/list')
       .then(function (response) {
           $scope.products = response.data;

           if (productId) {
               console.log("" + $("#product option").length);//for clarity
               $timeout(function () {
                   console.log("" + $("#product option").length);//for clarity
                   $('#product').val('number:'+productId);

               }, 200);
           }
       });
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.