angular.element vs document.getElementById atau pemilih jQuery dengan kontrol putaran (sibuk)

157

Saya menggunakan versi "Angularised" dari kontrol Spin, seperti yang didokumentasikan di sini: http://blog.xvitcoder.com/adding-a-weel-progress-indicator-to-your-angularjs-application/

Salah satu hal yang saya tidak suka tentang solusi yang ditampilkan adalah penggunaan jQuery di layanan yang secara efektif melampirkan kontrol putaran ke elemen DOM. Saya lebih suka menggunakan konstruksi sudut untuk mengakses elemen. Saya juga ingin menghindari "hard-coding" id elemen yang perlu dilampirkan oleh spinner dalam layanan dan alih-alih menggunakan arahan yang menetapkan id dalam layanan (singleton) sehingga pengguna layanan lain atau layanan itu sendiri tidak perlu tahu itu.

Saya berjuang dengan apa yang angular.element berikan kepada kami vs apa yang document.getElementById pada id elemen yang sama memberi kami. misalnya. Ini bekerja:

  var target = document.getElementById('appBusyIndicator');

Tak satu pun dari ini yang:

  var target = angular.element('#appBusyIndicator');
  var target = angular.element('appBusyIndicator');

Saya jelas melakukan sesuatu yang seharusnya jelas salah! Adakah yang bisa membantu?

Dengan asumsi saya bisa mendapatkan yang bekerja di atas, saya punya masalah yang sama dengan mencoba mengganti akses jQuery ke elemen: misalnya $(target).fadeIn('fast'); bekerja angular.element('#appBusyIndicator').fadeIn('fast')atau angular.element('appBusyIndicator').fadeIn('fast')tidak

Adakah yang bisa mengarahkan saya ke contoh dokumentasi yang menjelaskan penggunaan elemen "elemen" Angular vs elemen DOM? Sudut jelas "membungkus" elemen dengan properti sendiri, metode dll tetapi seringkali sulit untuk mendapatkan nilai aslinya. Misalnya jika saya memiliki <input type='number'>bidang dan saya ingin mengakses konten asli yang terlihat di ui ketika pengguna mengetik "-" (tanpa tanda kutip) saya tidak mendapatkan apa-apa, mungkin karena "type = number" berarti Angular menolak input meskipun terlihat di UI dan saya ingin melihatnya sehingga saya bisa mengujinya dan menghapusnya.

Setiap petunjuk / jawaban dihargai.

Terima kasih.

Irlandia
sumber
5
angular.element adalah objek jQlite atau objek jQuery jika Anda memuat jQuery.
Neil

Jawaban:

226

Itu bisa bekerja seperti itu:

var myElement = angular.element( document.querySelector( '#some-id' ) );

Anda membungkus panggilan Document.querySelector()Javascript asli ke dalam angular.element()panggilan. Jadi, Anda selalu mendapatkan elemen dalam objek jqLite atau jQuery , tergantung apakah jQuerytersedia / dimuat.

Dokumentasi resmi untuk angular.element:

Jika jQuery tersedia, angular.elementadalah alias untuk jQueryfungsi tersebut. Jika jQuery tidak tersedia, angular.elementdelegasikan ke subset bawaan AngularjQuery , yang disebut "jQuery lite" atau jqLite .

Semua referensi elemen Angularselalu dibungkus dengan jQuery atau jqLite(seperti argumen elemen dalam kompilasi arahan atau fungsi tautan). Mereka tidak pernah DOMreferensi mentah .

Jika Anda heran mengapa harus menggunakan document.querySelector(), silakan baca jawaban ini .

kaisar
sumber
41
Apa alasan seseorang lebih memilih document.querySelector ('# ...') daripada hanya menggunakan document.getElementById ()?
Kato
4
Anda juga dapat melakukan ini pada elemen sudut: var elDivParent = angular.element (elem [0] .querySelector ('# an-id')) ;, elem menjadi elemen sudut. Dengan cara ini Anda dapat mencari di dalam suatu elemen. Berguna untuk pengujian unit.
unludo
4
@ Kato Info lebih lanjut dalam jawaban ini . Semoga itu bisa membantu.
kaiser
bekerja dengan Google Maps API, dan ini bekerja: var autocomplete = new google.maps.places.Autocomplete( $document[0].querySelector('#address'), { types: ['geocode'], componentRestrictions: {country: 'us'} } );. Terima kasih atas tip @kaiser. Untuk beberapa alasan, peta api mengeluh bahwa apa yang saya lewati di param pertama bukan input saat saya gunakan angular.element(document.querySelector('#address')), tetapi semuanya baik-baik saja yang berakhir dengan baik.
nymo
49

Anda harus membaca dokumen elemen sudut jika Anda belum melakukannya, sehingga Anda dapat memahami apa yang didukung oleh jqLite dan apa yang tidak -jqlite adalah himpunan bagian dari jquery yang dibangun ke dalam sudut.

Para pemilih tidak akan bekerja dengan jqLite saja, karena pemilih oleh id tidak didukung.

  var target = angular.element('#appBusyIndicator');
  var target = angular.element('appBusyIndicator');

Jadi, baik:

  • Anda menggunakan jqLite saja, lebih terbatas daripada jquery, tetapi cukup di sebagian besar situasi.
  • atau Anda memasukkan lib jQuery lengkap di aplikasi Anda, dan menggunakannya seperti jquery biasa, di tempat-tempat yang benar-benar Anda butuhkan jquery.

Sunting: Perhatikan bahwa jQuery harus dimuat sebelum angularJS untuk diutamakan daripada jqLite:

Real jQuery selalu lebih diutamakan daripada jqLite, asalkan itu dimuat sebelum acara DOMContentLoaded dipecat.

Sunting2: Saya melewatkan bagian kedua dari pertanyaan sebelumnya:

Masalah dengan <input type="number">, saya pikir itu bukan masalah sudut, itu adalah perilaku yang dimaksudkan dari elemen nomor html5 asli .

Itu tidak akan mengembalikan nilai non-numerik bahkan jika Anda mencoba mengambilnya dengan jquery .val()atau dengan .valueatribut mentah .

Garst
sumber
2
Kami memiliki pustaka jQuery lengkap - jika $ skenario saya dijelaskan di atas tidak akan berfungsi. Pertanyaan saya ada di sekitar mengapa $ berfungsi tetapi angular.element tidak - meskipun jQuery lengkap tersedia.
Irlandia
1
Apakah Anda termasuk jQuery sebelum atau sesudah angular.js? Itu harus dimasukkan sebelum sudut. Penyeleksi oleh id melakukan pekerjaan dengan jQuery tersedia: jsbin.com/ohumiy/1/edit
Garst
1
Mereka bekerja di arahan lain (mis. Angular.element untuk mengakses sesuatu dengan id). Masalah tampaknya menjadi cara kontrol ini bekerja dengan melampirkan dirinya ke elemen itu, meskipun saya tidak mengerti mengapa jQuery yang sama secara langsung harus bekerja. Menggunakan jQuery secara langsung arahan saya HARUS memiliki tag penutup - tag penutup diri tidak berfungsi (tidak ada kesalahan hanya layar kosong) yang membuat saya curiga kontrol.
irascian
2
Pada poin ke-2 saya ada juga sesuatu seperti view $ value yang dapat digunakan untuk mengambil konten suatu elemen tetapi dalam kasus tipe input = angka di mana pengguna memiliki input "-" ini kosong. Saya ingin sesuatu properti seperti $ rawInputValue pada elemen untuk melihat konten SEBELUM Angular telah melangkah karena "-" masih di UI meskipun saya tidak memiliki akses ke sana secara programatik dalam arahan saya.
irascian
27
var target = document.getElementById('appBusyIndicator');

adalah sama dengan

var target = $document[0].getElementById('appBusyIndicator');
Dasun
sumber
1
Lebih baik menggunakan contoh kedua untuk memastikan bahwa dependensi Anda eksplisit dan dapat diejek, kan?
Lukas
seharusnya begitu, tapi saya kira Dalam angular 2+ kita hanya mengandalkan lebih pada fitur naskah. Tidak lagi perlu khawatir tentang hal-hal ini :)
Dasun
17

Saya tidak berpikir itu cara yang tepat untuk menggunakan sudut. Jika metode kerangka tidak ada, jangan buat itu! Ini berarti kerangka kerja (di sini bersudut) tidak bekerja dengan cara ini.

Dengan sudut Anda tidak boleh memanipulasi DOM seperti ini (cara jquery), tetapi gunakan penolong sudut seperti

<div ng-show="isLoading" class="loader"></div>

Atau buat direktif Anda sendiri (komponen DOM Anda sendiri) untuk memiliki kontrol penuh padanya.

BTW, Anda bisa lihat di sini http://caniuse.com/#search=queryselector querySelector didukung dengan baik sehingga dapat digunakan dengan aman.

Thomas Decaux
sumber
2
Anda benar sekali. 90% + dari kasus yang saya pikir saya perlu memanipulasi DOM secara manual, saya akhirnya refactoring kode untuk menghilangkan kebutuhan dan pada akhirnya kode jauh lebih bersih.
Stephen Chung
17

Jika seseorang menggunakan tegukan, itu menunjukkan kesalahan jika kita menggunakan document.getElementById()dan itu menyarankan untuk digunakan $document.getElementById()tetapi tidak berhasil.

Gunakan -

$document[0].getElementById('id')
Kanchan
sumber
Mengapa sudut menyuntikkan array di sini?
Peter
16

Anda dapat mengakses elemen menggunakan $ document ($ document perlu disuntikkan)

var target = $document('#appBusyIndicator');
var target = $document('appBusyIndicator');

atau dengan elemen sudut, elemen yang ditentukan dapat diakses sebagai:

var targets = angular.element(document).find('div'); //array of all div
var targets = angular.element(document).find('p');
var target = angular.element(document).find('#appBusyIndicator');
Nishant Baranwal
sumber
1
find () - Terbatas untuk pencarian dengan nama tag
RJV
angular.element (document) .find ('. someClass'); bekerja dengan sangat baik.
Nishant Baranwal
10

Anda harus menyuntikkan $ document pada controller Anda, dan menggunakannya sebagai ganti objek dokumen asli.

var myElement = angular.element($document[0].querySelector('#MyID'))

Jika Anda tidak memerlukan bungkus elemen gaya jquery, $ document [0] .querySelector ('# MyID') akan memberi Anda objek DOM.

Adamy
sumber
1
Anda juga bisa langsung mereferensikan window.document secara langsung daripada menggunakan Angulars $ overhead layanan dokumen.
MatBee
5
Tentu saja Anda bisa jika Anda tidak khawatir tentang mengejek $ dokumen di unittest Anda
Adamy
Tidak jelas bagi saya: Saya mendapatkan warnig ini: Anda harus menggunakan layanan $ document sebagai ganti objek dokumen default, tetapi apa artinya? Adakah dokumen tentang itu? Terima kasih!
realnot
@realnot Anda dapat mengakses Objek Dokumen DOM HTML dari mana saja di javascript Anda. w3schools.com/jsref/dom_obj_document.asp
Adamy
6

Ini bekerja dengan baik untuk saya.

angular.forEach(element.find('div'), function(node)
{
  if(node.id == 'someid'){
    //do something
  }
  if(node.className == 'someclass'){
    //do something
  }
});
susrut316
sumber
3
elemen tidak terdefinisi? angular.element.find bukan fungsi bagi saya untuk mencoba Anda tanpa JQuery.
mendarat
3
Tolong jangan lakukan ini. Gunakan salah satu contoh lainnya. Ini tidak menggunakan optimasi pencarian tabel hash sama sekali.
MatBee
4

Peningkatan jawaban kaiser:

var myEl = $document.find('#some-id');

Jangan lupa untuk menyuntikkan $documentke direktif Anda

Rob H
sumber
21
Seperti disebutkan dalam dokumentasi sudut untuk element.find : find() - Limited to lookups by tag name, itu tidak bekerja pada id. Anda juga memiliki penutupan ekstra ).
paaat
3

Mungkin saya terlambat di sini tetapi ini akan berhasil:

var target = angular.element(appBusyIndicator);

Perhatikan, tidak ada appBusyIndicator, itu adalah nilai ID polos.

Apa yang terjadi di balik layar: (dengan asumsi itu diterapkan pada div) (diambil dari angular.js baris no: 2769 dan seterusnya ...)

/////////////////////////////////////////////
function JQLite(element) {     //element = div#appBusyIndicator
  if (element instanceof JQLite) {
    return element;
  }

  var argIsString;

  if (isString(element)) {
    element = trim(element);
    argIsString = true;
  }
  if (!(this instanceof JQLite)) {
    if (argIsString && element.charAt(0) != '<') {
      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
    }
    return new JQLite(element);
  }

Secara default jika tidak ada jQuery di halaman, jqLite akan digunakan. Argumen ini dipahami secara internal sebagai id dan objek jQuery yang sesuai dikembalikan.

Vishal Anand
sumber
Saya sudah mencoba ini sekarang dengan Angular 1.5.8. ID polos mengembalikan hasil kosong. angular.element("#myId")bekerja dengan baik.
Gosha U.
mungkin Anda punya jQuery di halaman Anda?
Vishal Anand