Bekerja dengan memilih menggunakan opsi-AngularJS

442

Saya telah membacanya di posting lain, tetapi saya tidak bisa mengetahuinya.

Saya memiliki sebuah array,

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

Saya ingin menjadikannya sebagai:

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

Dan saya juga ingin memilih opsi dengan ID = 000002.

Saya telah membaca pilih dan mencoba, tetapi saya tidak dapat menemukannya.

Andrej Kaurin
sumber
Saya sangat merekomendasikan menggunakan Select2 , karena ini akan menangani ini untuk Anda. Bahkan ada arahan untuk AngularJS .
hewstone
Sebenarnya ada solusi AngularJS murni yang dikembangkan oleh QuantumUI . Anda dapat menemukan lebih banyak contoh dan dokumentasi di http://quantumui.org/ .
Ramon Drunce

Jawaban:

799

Satu hal yang perlu diperhatikan adalah ngModel diperlukan agar ngOptions berfungsi ... perhatikan ng-model="blah"yang berbunyi "set $ scope.blah ke nilai yang dipilih".

Coba ini:

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

Berikut ini lebih banyak dari dokumentasi AngularJS (jika Anda belum melihatnya):

untuk sumber data array:

  • label untuk nilai dalam array
  • pilih sebagai label untuk nilai dalam array
  • label grup demi grup untuk nilai dalam array = pilih sebagai grup label dengan grup untuk nilai dalam array

untuk sumber data objek:

  • label untuk (kunci, nilai) pada objek
  • pilih sebagai label untuk (kunci, nilai) pada objek
  • label grup demi grup untuk (kunci, nilai) dalam objek
  • pilih sebagai grup label dengan grup untuk (kunci, nilai) dalam objek

Untuk beberapa klarifikasi tentang nilai tag opsi di AngularJS:

Ketika Anda menggunakan ng-options, nilai tag opsi yang ditulis oleh ng-options akan selalu menjadi indeks item array yang terkait dengan tag opsi . Ini karena AngularJS sebenarnya memungkinkan Anda untuk memilih seluruh objek dengan kontrol pilih, dan bukan hanya tipe primitif. Sebagai contoh:

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>

Di atas akan memungkinkan Anda untuk memilih seluruh objek menjadi $scope.selectedItemlangsung. Intinya, dengan AngularJS, Anda tidak perlu khawatir tentang apa yang ada di tag pilihan Anda. Biarkan AngularJS mengatasinya; Anda hanya harus peduli tentang apa yang ada dalam model Anda di ruang lingkup Anda.

Di sini ada seorang plunker yang menunjukkan perilaku di atas, dan menunjukkan HTML yang ditulis


Berurusan dengan opsi default:

Ada beberapa hal yang saya gagal sebutkan di atas berkaitan dengan opsi default.

Memilih opsi pertama dan menghapus opsi kosong:

Anda dapat melakukan ini dengan menambahkan sederhana ng-inityang menetapkan model (dari ng-model) ke elemen pertama dalam item yang Anda ulangi ng-options:

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

Catatan: Ini bisa menjadi sedikit gila jika fookebetulan diinisialisasi dengan benar ke sesuatu yang "palsu". Dalam hal ini, Anda mungkin ingin menangani inisialisasi foodi controller Anda, kemungkinan besar.

Menyesuaikan opsi default:

Ini sedikit berbeda; di sini yang perlu Anda lakukan adalah menambahkan tag opsi sebagai anak pilihan Anda, dengan atribut nilai kosong, lalu sesuaikan teks dalamnya:

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

Catatan: Dalam hal ini opsi "kosong" akan tetap ada bahkan setelah Anda memilih opsi lain. Ini bukan kasus untuk perilaku default pilihan di bawah AngularJS.

Opsi default khusus yang bersembunyi setelah seleksi dibuat:

Jika Anda ingin opsi default khusus Anda hilang setelah Anda memilih nilai, Anda bisa menambahkan atribut ng-hide ke opsi default Anda:

<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>
Ben Lesh
sumber
3
Ternyata itu adalah indeks nilai, ini adalah bagaimana sudut dapat memungkinkan Anda untuk menggunakan objek sebagai nilai dari kotak pilih Anda. Angular melakukan banyak hal untuk Anda di belakang layar dengan kotak pilih, dan Anda tidak perlu khawatir tentang atribut nilai pada opsi Anda.
Ben Lesh
1
Dokumentasi berada di bawah "pilih" di situs mereka: docs.angularjs.org/api/ng.directive:select
Ben Lesh
25
"... ngModel diperlukan agar Pilihan bekerja ..." adalah inti masalahnya bagiku. Jawaban yang bagus.
tristanm
1
Apakah mungkin untuk menghindari opsi kosong pertama ( <option value="?" selected="selected"></option>)?
swenedo
4
Saya mencoba menggunakan case terakhir ( Opsi default khusus yang bersembunyi setelah seleksi dibuat ) tetapi saya menemukan beberapa masalah. Alih-alih ng-if="foo"saya harus menggunakan ng-if=!foountuk menyembunyikan opsi kosong default ketika opsi lain dipilih. Juga, opsi kosong standar selalu muncul di bagian bawah daftar kombo. Bagaimana saya bisa meletakkannya di awal daftar kombo?
Fran Herrero
90

Saya belajar AngularJS dan berjuang dengan seleksi juga. Saya tahu pertanyaan ini sudah dijawab, tetapi saya ingin berbagi beberapa kode lagi.

Dalam pengujian saya, saya memiliki dua kotak daftar: merek mobil dan model mobil. Daftar model dinonaktifkan hingga beberapa make dipilih. Jika pilihan dalam make listbox kemudian diatur ulang (atur ke 'Select Make') maka kotak daftar model menjadi dinonaktifkan lagi DAN pemilihannya diatur ulang juga (ke 'Select Model'). Makes diambil sebagai sumber daya sementara model hanya kode keras.

Membuat JSON:

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

layanan.js:

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

File 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"};
}
mp31415
sumber
27
Pengguna acak yang terhormat. Meskipun pertanyaan dan jawabannya agak sederhana dan tidak rumit, organisasi kode Anda ke lokasi yang sesuai dan masing-masing (pengontrol, layanan, templat, data) menunjukkan keanggunan AngularJS dalam bentuknya yang paling sederhana dan standar. Contoh yang luar biasa.
Atticus
1
Ini bukan bagaimana seharusnya digunakan. ng-modelharus menunjuk ke variabel lain pada ruang lingkup Anda, tidak terkait dengan make. Lihat contoh di docs.angularjs.org/api/ng/directive/ngOptions
Dmitri Zaitsev
@ DmitriZaitsev Saya pikir Anda salah, hanya karena contoh dokumen sudut menunjukkan cara Anda menggambarkan tidak berarti itu satu-satunya cara. Tunjukkan pada kami mengapa Anda pikir itu tidak seharusnya digunakan dengan cara ini daripada menggosok contoh yang bagus untuk pemula.
JRT
39

Untuk beberapa alasan, AngularJS membuat saya bingung. Dokumentasi mereka sangat mengerikan dalam hal ini. Contoh variasi yang lebih baik akan diterima.

Bagaimanapun, saya memiliki sedikit variasi pada jawaban Ben Lesh.

Koleksi data saya terlihat seperti ini:

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

Sekarang

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

masih menghasilkan nilai opsi menjadi indeks (0, 1, 2, dll.).

Menambahkan Track Dengan memperbaikinya untuk saya:

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

Saya rasa itu lebih sering terjadi bahwa Anda ingin menambahkan array objek ke daftar pilih, jadi saya akan mengingat yang satu ini!

Ketahuilah bahwa dari AngularJS 1.4 Anda tidak dapat menggunakan opsi-ng lagi, tetapi Anda perlu menggunakannya ng-repeatpada tag opsi Anda:

<select name="test">
   <option ng-repeat="item in items" value="{{item.key}}">{{item.value}}</option>
</select>
Mattijs
sumber
3
Jawaban ini tampaknya persis seperti apa yang ditanyakan. Setiap jawaban lain memberitahu pembaca untuk tidak khawatir tentang apa yang dihasilkan HTML, tetapi jika elemen pilih dalam bentuk, saya sangat khawatir. Jawaban bagus!
Keith
3
Harus ditunjukkan bahwa ini menyimpan objek yang dipilih penuh dalam model, bukan hanya kunci. Jika Anda hanya ingin kunci dalam model, Anda ingin menggunakan versi "item.key as item.value". Ini membingungkan saya untuk sementara waktu ketika saya terpaku pada apa yang tampak seperti HTML, bukan data yang saya inginkan dalam model, yang, bagi saya, yang penting.
mhenry1384
@ mhenry1384 Ya Anda benar, tentang itu menyimpan seluruh objek. Saya sebenarnya suka fitur itu karena memberi Anda akses ke lebih dari sekedar ID (jika Anda membutuhkannya.). Bekerja dengan baik untuk saya ketika saya mengisi daftar dengan koleksi mongo dan saya butuh properti dari item yang dipilih.
Mattijs
2
Dan bagaimana kita bisa mendeteksi perubahan dengan "ng-ubah" di dalamnya option?
Konstantinos Natsios
2
Mengenai Pembaruan, ini tidak beres. ng-opsi masih berfungsi dengan baik di 1.5. Itu juga masih menunjukkan dalam dokumentasi. docs.angularjs.org/api/ng/directive/select
Jeremy A. West
15

Pertanyaannya sudah dijawab (BTW, jawaban yang benar-benar bagus dan komprehensif disediakan oleh Ben), tetapi saya ingin menambahkan elemen lain untuk kelengkapan, yang mungkin juga sangat berguna.

Dalam contoh yang disarankan oleh Ben:

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

berikut ngOptions bentuk telah digunakan: select as label for value in array.

Label adalah ekspresi, yang hasilnya akan menjadi label untuk <option>elemen. Dalam hal ini Anda dapat melakukan penggabungan string tertentu, untuk memiliki label opsi yang lebih kompleks.

Contoh:

  • ng-options="item.ID as item.Title + ' - ' + item.ID for item in items" memberi Anda label suka Title - ID
  • ng-options="item.ID as item.Title + ' (' + item.Title.length + ')' for item in items"memberi Anda label seperti Title (X), di mana Xpanjang string Judul.

Anda juga dapat menggunakan filter, misalnya,

  • ng-options="item.ID as item.Title + ' (' + (item.Title | uppercase) + ')' for item in items"memberi Anda label seperti Title (TITLE), di mana nilai Judul properti Judul dan TITLE adalah nilai yang sama tetapi dikonversi ke karakter huruf besar.
  • ng-options="item.ID as item.Title + ' (' + (item.SomeDate | date) + ')' for item in items"memberi Anda label seperti Title (27 Sep 2015), jika model Anda memiliki propertiSomeDate
Tom
sumber
7

Dalam 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>
Akatsuki Sai
sumber
1
Jangan lupa radixuntuk parseInt: http://davidwalsh.name/parseint-radix
GFoley83
6

Jika Anda memerlukan judul khusus untuk setiap opsi, ng-optionstidak berlaku. Alih-alih gunakan ng-repeatdengan opsi:

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

Saya harap yang berikut ini akan berhasil untuk Anda.

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

Ini bisa bermanfaat. Binding tidak selalu berfungsi.

<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>

Misalnya, Anda mengisi model sumber daftar opsi dari layanan REST. Nilai yang dipilih diketahui sebelum mengisi daftar, dan itu ditetapkan. Setelah menjalankan permintaan REST dengan $ http, opsi daftar selesai.

Tetapi opsi yang dipilih tidak diatur. Untuk alasan yang tidak diketahui AngularJS dalam menjalankan shadow $ digest tidak mengikat sebagaimana yang seharusnya. Saya harus menggunakan jQuery untuk mengatur yang dipilih. Itu penting! AngularJS, dalam bayangan, menambahkan awalan ke nilai attr "value" untuk dihasilkan oleh opsi ng-repeat. Untuk int itu adalah "nomor:".

$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);
           }
       });
}
trueboroda
sumber