angular.element เทียบกับ document.getElementById หรือตัวเลือก jQuery พร้อมตัวควบคุมการหมุน (ไม่ว่าง)


157

ฉันใช้การควบคุมการหมุนแบบ "เชิงมุม" ตามที่บันทึกไว้ที่นี่: http://blog.xvitcoder.com/adding-a-weel-progress-indicator-to-your-angularjs-application/

สิ่งหนึ่งที่ฉันไม่ชอบเกี่ยวกับโซลูชันที่แสดงคือการใช้ jQuery ในบริการที่แนบการควบคุมการหมุนกับองค์ประกอบ DOM อย่างมีประสิทธิภาพ ฉันต้องการใช้โครงสร้างเชิงมุมเพื่อเข้าถึงองค์ประกอบ ฉันต้องการหลีกเลี่ยง "hard-coding" id ขององค์ประกอบที่สปินเนอร์จำเป็นต้องแนบภายในบริการและใช้ directive ที่กำหนด id ในบริการ (singleton) เพื่อให้ผู้ใช้บริการรายอื่นหรือ บริการไม่จำเป็นต้องรู้

ฉันกำลังดิ้นรนกับสิ่งที่ angular.element ให้เรากับสิ่งที่ document.getElementById ในองค์ประกอบ id เดียวกันให้เรา เช่น. งานนี้:

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

สิ่งเหล่านี้ไม่ได้ทำ:

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

ฉันกำลังทำสิ่งที่ชัดเจนผิดอย่างชัดเจน! ผู้ใดช่วยได้บ้าง

สมมติว่าฉันสามารถทำงานได้ดังกล่าวข้างต้นฉันมีปัญหาที่คล้ายกันกับการพยายามแทนที่การเข้าถึงองค์ประกอบ jQuery: เช่น$(target).fadeIn('fast'); ทำงาน angular.element('#appBusyIndicator').fadeIn('fast')หรือangular.element('appBusyIndicator').fadeIn('fast')ไม่

ใครสามารถชี้ให้ฉันเป็นตัวอย่างที่ดีของเอกสารที่ชี้แจงการใช้ "องค์ประกอบ" เชิงมุมกับองค์ประกอบ DOM หรือไม่ เห็นได้ชัดว่า Angular "ล้อม" องค์ประกอบด้วยคุณสมบัติของตัวเองวิธีการอื่น ๆ แต่มักจะยากที่จะรับค่าดั้งเดิม ตัวอย่างเช่นถ้าฉันมี<input type='number'>ฟิลด์และฉันต้องการเข้าถึงเนื้อหาต้นฉบับที่ปรากฏใน UI เมื่อผู้ใช้พิมพ์ "-" (โดยไม่มีเครื่องหมายอัญประกาศ) ฉันไม่ได้รับอะไรเลยสันนิษฐานเพราะ "type = number" หมายความว่าแองกูลาร์กำลังปฏิเสธ อินพุตแม้ว่าจะมองเห็นได้ใน UI และฉันต้องการดูดังนั้นฉันสามารถทดสอบและล้างมันได้

คำแนะนำ / คำตอบใด ๆ ชื่นชม

ขอบคุณ


5
angular.element เป็นวัตถุ jQlite หรือวัตถุ jQuery หากคุณกำลังโหลด jQuery
Neil

คำตอบ:


226

มันสามารถทำงานได้:

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

คุณตัดการโทรDocument.querySelector()จาวาสคริปต์ดั้งเดิมลงในการangular.element()โทร ดังนั้นคุณจะได้รับองค์ประกอบในวัตถุjqLiteหรือjQueryเสมอขึ้นอยู่กับว่าjQueryมี / โหลดหรือไม่

เอกสารอย่างเป็นทางการสำหรับangular.element:

หากjQueryพร้อมใช้งานangular.elementจะเป็นนามแฝงสำหรับjQueryฟังก์ชั่น หาก jQuery ไม่สามารถใช้งานangular.elementได้รับมอบหมายให้เชิงมุม s ในตัวของเซตjQueryที่เรียกว่า "jQuery Lite" หรือjqLite

การอ้างอิงองค์ประกอบทั้งหมดในAngularนั้นจะถูกห่อด้วยjQueryหรือjqLite(เช่นอาร์กิวเมนต์องค์ประกอบในคำสั่งคอมไพล์หรือฟังก์ชันลิงก์) พวกเขาจะไม่DOMอ้างอิงดิบ

ในกรณีที่คุณสงสัยว่าทำไมต้องใช้document.querySelector()โปรดอ่านคำตอบนี้


41
มีเหตุผลใดที่คุณต้องการให้ document.querySelector ('# ... ') เพียงแค่ใช้ document.getElementById ()
Kato

4
คุณอาจทำสิ่งนี้กับองค์ประกอบเชิงมุม: var elDivParent = angular.element (elem [0] .querySelector ('# an-id')); elem เป็นองค์ประกอบเชิงมุม วิธีนี้คุณสามารถค้นหาภายในองค์ประกอบ มีประโยชน์สำหรับการทดสอบหน่วย
แยก

4
@Kato ข้อมูลเพิ่มเติมในคำตอบนี้ หวังว่าจะช่วย
ไกเซอร์

การทำงานร่วมกับ Google Maps API var autocomplete = new google.maps.places.Autocomplete( $document[0].querySelector('#address'), { types: ['geocode'], componentRestrictions: {country: 'us'} } );และนี้ทำงาน: ขอบคุณสำหรับเคล็ดลับ @kaiser ด้วยเหตุผลบางอย่างแผนที่ api บ่นว่าสิ่งที่ฉันส่งผ่านใน param แรกไม่ใช่อินพุตเมื่อฉันใช้angular.element(document.querySelector('#address'))แต่ทุกอย่างก็จบลงด้วยดี
nymo

49

คุณควรอ่านเอกสารองค์ประกอบเชิงมุมถ้าคุณยังไม่ได้ดังนั้นคุณสามารถเข้าใจสิ่งที่ได้รับการสนับสนุนโดย jqLite และสิ่งที่ไม่ได้ -jqlite เป็นส่วนหนึ่งของ jquery สร้างขึ้นในเชิงมุม

ตัวเลือกเหล่านั้นจะไม่ทำงานกับ jqLite เพียงอย่างเดียวเนื่องจากตัวเลือกตาม id ไม่ได้รับการสนับสนุน

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

ดังนั้นทั้ง:

  • คุณใช้ jqLite เพียงอย่างเดียว จำกัด มากกว่า jquery แต่เพียงพอในสถานการณ์ส่วนใหญ่
  • หรือคุณรวม jQuery lib แบบเต็มในแอปของคุณและใช้มันเหมือนกับ jquery ปกติในสถานที่ที่คุณต้องการ jquery

แก้ไข: โปรดทราบว่าควรโหลด jQuery ก่อน angularJS เพื่อให้มีความสำคัญเหนือกว่า jqLite:

jQuery จริงมีความสำคัญมากกว่า jqLite เสมอหากถูกโหลดก่อนที่จะเกิดเหตุการณ์ DOMContentLoaded

แก้ไข 2: ฉันพลาดส่วนที่สองของคำถามมาก่อน:

ปัญหาเกี่ยวกับ<input type="number">ฉันคิดว่ามันไม่ใช่ปัญหาเชิงมุมมันเป็นพฤติกรรมที่ตั้งใจไว้ขององค์ประกอบหมายเลข html5 ดั้งเดิม

มันจะไม่ส่งคืนค่าที่ไม่ใช่ตัวเลขแม้ว่าคุณจะพยายามเรียกคืนด้วย jquery's .val()หรือด้วย.valueแอตทริบิวต์raw


2
เรามีไลบรารี่ jQuery เต็ม - มิฉะนั้นสถานการณ์ $ ของฉันที่อธิบายข้างต้นจะไม่ทำงาน คำถามของฉันอยู่ที่ว่าทำไม $ ทำงาน แต่ angular.element ไม่ได้ - แม้ว่าจะมี jQuery แบบเต็ม
irascian

1
คุณรวม jQuery ก่อนหรือหลัง angular.js หรือไม่ มันควรจะรวมก่อนที่เชิงมุม Selectors คุณ id ทำทำงานกับ jQuery ที่ใช้ได้: jsbin.com/ohumiy/1/edit
garst

1
พวกเขากำลังทำงานในคำสั่งอื่น (เช่น angular.element เพื่อเข้าถึงบางสิ่งบางอย่างโดย id) ปัญหาดูเหมือนจะเป็นวิธีการควบคุมนี้ทำงานโดยแนบตัวเองกับองค์ประกอบที่แม้ว่าฉันไม่เข้าใจว่าทำไม jQuery เดียวกันที่เทียบเท่าควรทำงานโดยตรง การใช้ jQuery โดยตรง HAS directive ของฉันที่จะมีแท็กปิด - แท็กปิดตัวเองไม่ทำงาน (ไม่มีข้อผิดพลาดเพียงแค่หน้าจอว่าง) ซึ่งทำให้ฉันสงสัยว่าตัวควบคุม
irascian

2
ในจุดที่ 2 ของฉันมีบางสิ่งเช่น view $ value ซึ่งสามารถใช้เพื่อดึงเนื้อหาขององค์ประกอบ แต่ในกรณีของ input type = number ที่ผู้ใช้มีอินพุต "-" นี่ว่างเปล่า ฉันต้องการคุณสมบัติบางอย่างเช่น $ rawInputValue บนองค์ประกอบเพื่อดูเนื้อหาก่อนที่ Angular ได้ก้าวเข้ามาเพราะ "-" ยังคงอยู่ใน UI แม้ว่าฉันจะไม่สามารถเข้าถึงได้ตามคำสั่งของฉัน
irascian

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

เท่ากับ

var target = $document[0].getElementById('appBusyIndicator');

1
มันจะดีกว่าถ้าใช้ตัวอย่างที่สองเพื่อให้แน่ใจว่าการอ้างอิงของคุณชัดเจนและสามารถล้อเลียนใช่ไหม?
ลุค

มันควรจะเป็น แต่ฉันเดาว่าในเชิงมุม 2+ เราพึ่งคุณลักษณะของตัวพิมพ์ ไม่ต้องกังวลเกี่ยวกับสิ่งเหล่า :)
Dasun

17

ฉันไม่คิดว่ามันเป็นวิธีที่เหมาะสมในการใช้เชิงมุม หากไม่มีวิธีการของเฟรมเวิร์กอย่าสร้างมันขึ้นมา! นี่หมายความว่าเฟรมเวิร์ก (ที่นี่เป็นมุม) ไม่ทำงานในลักษณะนี้

ด้วยเชิงมุมคุณไม่ควรใช้ DOM แบบนี้ (วิธี jquery) แต่ใช้ตัวช่วยเชิงมุมเช่น

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

หรือสร้างคำสั่งของคุณเอง (คอมโพเนนต์ DOM ของคุณเอง) เพื่อให้สามารถควบคุมได้อย่างเต็มที่

BTW คุณสามารถดูได้ที่นี่http://caniuse.com/#search=queryselector querySelector ได้รับการสนับสนุนเป็นอย่างดีและสามารถใช้งานได้อย่างปลอดภัย


2
คุณพูดถูก 90% + ของกรณีที่ฉันคิดว่าฉันต้องจัดการ DOM ด้วยตนเองฉันลงเอยด้วยการปรับโครงสร้างรหัสใหม่เพื่อลบความต้องการออกและท้ายที่สุดรหัสก็สะอาดกว่ามาก
Stephen Chung

17

หากมีคนใช้อึกแสดงว่ามีข้อผิดพลาดถ้าเราใช้document.getElementById()และมันแนะนำให้ใช้$document.getElementById()แต่มันไม่ทำงาน

ใช้ -

$document[0].getElementById('id')

เหตุใดแองกูลาร์จึงฉีดอาร์เรย์ที่นี่
ปีเตอร์

16

คุณสามารถเข้าถึงองค์ประกอบโดยใช้ $ document (ต้องใส่เอกสาร $)

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

หรือด้วยองค์ประกอบเชิงมุมองค์ประกอบที่ระบุสามารถเข้าถึงได้เป็น:

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');

1
find () - จำกัด การค้นหาตามชื่อแท็ก
RJV

angular.element (เอกสาร) ประจำวันหา (' SomeClass.); ทำงานได้ดีอย่างสมบูรณ์แบบ
Nishant Baranwal

10

คุณควรฉีด $ document ในคอนโทรลเลอร์ของคุณและใช้มันแทนวัตถุเอกสารต้นฉบับ

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

หากคุณไม่ต้องการห่อองค์ประกอบสไตล์ jquery $ document [0] .querySelector ('# MyID') จะให้วัตถุ DOM แก่คุณ


1
คุณอาจอ้างอิง window.document โดยตรงแทนที่จะใช้ค่าใช้จ่ายของบริการเอกสาร Angulars $
MatBee

5
แน่นอนคุณสามารถถ้าคุณไม่ต้องกังวลเกี่ยวกับการเยาะเย้ย $ เอกสารใน UnitTest ของคุณ
Adamy

ไม่ชัดเจนสำหรับฉัน: ฉันได้รับคำเตือนนี้: คุณควรใช้บริการ $ document แทนวัตถุเอกสารเริ่มต้น แต่มันหมายถึงอะไร? มีเอกสารเกี่ยวกับเรื่องนี้หรือไม่? ขอบคุณ!
realnot

@ ไม่จริงคุณสามารถเข้าถึง HTML DOM Document Document จากที่ใดก็ได้ใน javascript ของคุณ w3schools.com/jsref/dom_obj_document.asp
Adamy

6

มันใช้งานได้ดีสำหรับฉัน

angular.forEach(element.find('div'), function(node)
{
  if(node.id == 'someid'){
    //do something
  }
  if(node.className == 'someclass'){
    //do something
  }
});

3
องค์ประกอบไม่ได้กำหนด? angular.element.find ไม่ใช่ฟังก์ชั่นสำหรับฉันที่ลองใช้ของคุณโดยไม่มี JQuery
ลงจอด

3
โปรดอย่าทำเช่นนี้ ใช้หนึ่งในตัวอย่างอื่น ๆ สิ่งนี้ใช้การปรับตารางการค้นหาแบบแฮชไม่ได้เลย
MatBee

4

ปรับปรุงเป็นคำตอบของ kaiser:

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

อย่าลืมที่จะฉีด$documentเข้าไปในคำสั่งของคุณ


21
ดังที่กล่าวไว้ในเอกสารประกอบเชิงมุมสำหรับelement.find : find() - Limited to lookups by tag nameมันไม่ทำงานบนรหัส )นอกจากนี้คุณมีการปิดพิเศษ
paaat

3

บางทีฉันอาจจะสายเกินไปที่นี่ แต่มันจะใช้ได้:

var target = angular.element(appBusyIndicator);

ขอให้สังเกตว่าไม่มีappBusyIndicatorมันเป็นค่า ID ธรรมดา

สิ่งที่เกิดขึ้นเบื้องหลัง: (สมมติว่ามันใช้กับ div) (นำมาจาก angular.js บรรทัดที่: 2769 เป็นต้นไป ... )

/////////////////////////////////////////////
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);
  }

โดยค่าเริ่มต้นหากไม่มี jQuery ในหน้านั้นจะใช้ jqLite มีการเข้าใจอาร์กิวเมนต์ภายในว่าเป็น id และส่งคืนวัตถุ jQuery ที่สอดคล้องกัน


ฉันลองสิ่งนี้ตอนนี้ด้วย Angular 1.5.8 ID ธรรมดาส่งกลับผลลัพธ์ที่ว่างเปล่า angular.element("#myId")ทำได้ดี.
Gosha U.

คุณอาจจะมี jQuery บนหน้าของคุณ?
Vishal Anand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.