angle.element vs document.getElementById oder jQuery-Selektor mit Spin-Steuerung (Besetzt)

157

Ich verwende die "Angularised" -Version des Spin-Steuerelements, wie hier dokumentiert: http://blog.xvitcoder.com/adding-a-weel-progress-indicator-to-your-angularjs-application/

Eines der Dinge, die ich an der gezeigten Lösung nicht mag, ist die Verwendung von jQuery im Service, mit dem die Spinsteuerung effektiv an das DOM-Element angehängt wird. Ich würde es vorziehen, eckige Konstrukte zu verwenden, um auf das Element zuzugreifen. Ich möchte auch vermeiden, die ID des Elements, an das der Spinner innerhalb des Dienstes anhängen muss, "fest zu codieren", und stattdessen eine Direktive verwenden, die die ID im Dienst (Singleton) so festlegt, dass andere Benutzer des Dienstes oder Der Service selbst muss das nicht wissen.

Ich kämpfe mit dem, was angle.element uns gibt, und dem, was document.getElementById auf derselben Element-ID uns gibt. z.B. Das funktioniert:

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

Nichts davon tut:

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

Ich mache eindeutig etwas, das ziemlich offensichtlich falsch sein sollte! Kann jemand helfen?

Angenommen, ich kann das oben genannte zum Laufen bringen, habe ich ein ähnliches Problem beim Versuch, den jQuery-Zugriff auf das Element zu ersetzen: zB $(target).fadeIn('fast'); funktioniert angular.element('#appBusyIndicator').fadeIn('fast')oder angular.element('appBusyIndicator').fadeIn('fast')nicht

Kann mich jemand auf ein gutes Beispiel für eine Dokumentation verweisen, die die Verwendung eines Angular- "Elements" gegenüber dem DOM-Element verdeutlicht? Angular "umschließt" das Element offensichtlich mit seinen eigenen Eigenschaften, Methoden usw., aber es ist oft schwierig, den ursprünglichen Wert zu erhalten. Wenn ich zum Beispiel ein <input type='number'>Feld habe und auf den ursprünglichen Inhalt zugreifen möchte, der in der Benutzeroberfläche sichtbar ist, wenn der Benutzer "-" (ohne Anführungszeichen) eingibt, erhalte ich nichts, vermutlich weil "type = number" bedeutet, dass Angular ablehnt Die Eingabe, obwohl sie in der Benutzeroberfläche sichtbar ist und ich sie sehen möchte, damit ich sie testen und löschen kann.

Alle Hinweise / Antworten geschätzt.

Vielen Dank.

irascian
quelle
5
angle.element ist ein jQlite-Objekt oder ein jQuery-Objekt, wenn Sie jQuery laden.
Neil

Antworten:

226

Es kann so funktionieren:

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

Sie verpacken den Document.querySelector()nativen Javascript- Aufruf in den angular.element()Aufruf. Sie erhalten das Element also immer in einem jqLite- oder jQuery- Objekt, je nachdem, ob jQueryes verfügbar / geladen ist oder nicht .

Offizielle Dokumentation für angular.element:

Wenn jQuery verfügbar ist, angular.elementist dies ein Alias ​​für die jQueryFunktion. Wenn jQuery nicht verfügbar ist, angular.elementdelegieren Sie an Angulars integrierte Teilmenge von jQuery"jQuery lite" oder " jqLite" .

Alle Elementreferenzen in Angularwerden immer mit jQuery oder umschlossenjqLite (z. B. das Elementargument in einer Kompilierungs- oder Verknüpfungsfunktion von Direktiven). Sie sind niemals rohe DOMReferenzen.

Falls Sie sich fragen, warum Sie es verwenden sollen document.querySelector(), lesen Sie bitte diese Antwort .

Kaiser
quelle
41
Gibt es einen Grund, warum man document.querySelector ('# ...') der einfachen Verwendung von document.getElementById () vorziehen würde?
Kato
4
Sie können dies auch für ein Winkelelement tun: var elDivParent = angle.element (elem [0] .querySelector ('# an-id')); wobei elem ein Winkelelement ist. Auf diese Weise können Sie innerhalb eines Elements suchen. Nützlich für Unit-Tests.
Unludo
4
@Kato Weitere Infos in dieser Antwort . Hoffentlich hilft das.
Kaiser
Arbeiten mit Google Maps API, und dies funktionierte : var autocomplete = new google.maps.places.Autocomplete( $document[0].querySelector('#address'), { types: ['geocode'], componentRestrictions: {country: 'us'} } );. Danke für den Tipp @kaiser. Aus irgendeinem Grund beschwerte sich die Maps-API, dass das, was ich im ersten Parameter übergeben habe, keine Eingabe war, als ich es verwendete angular.element(document.querySelector('#address')), aber alles ist gut, das endet gut.
Nymo
49

Sie sollten die Winkel lesen Element docs , wenn Sie noch nicht haben, so können Sie verstehen , was mit jqLite unterstützt wird und was nicht -jqlite eine Teilmenge von Jquery in Winkel gebaut ist.

Diese Selektoren funktionieren nicht nur mit jqLite, da Selektoren nach ID nicht unterstützt werden.

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

Also entweder :

  • Sie verwenden jqLite allein, eingeschränkter als jquery, aber in den meisten Situationen ausreichend.
  • oder Sie fügen die vollständige jQuery-Bibliothek in Ihre App ein und verwenden sie wie normale jquery an den Stellen, an denen Sie jquery wirklich benötigen.

Bearbeiten: Beachten Sie, dass jQuery vor angleJS geladen werden sollte, um Vorrang vor jqLite zu haben:

Echte jQuery hat immer Vorrang vor jqLite, vorausgesetzt, sie wurde vor dem Auslösen des DOMContentLoaded-Ereignisses geladen.

Edit2: Ich habe den zweiten Teil der Frage schon einmal verpasst:

Das Problem mit <input type="number">, ich denke, es ist kein Winkelproblem, es ist das beabsichtigte Verhalten des nativen HTML5-Zahlenelements.

Es wird kein nicht numerischer Wert zurückgegeben, selbst wenn Sie versuchen, ihn mit jquery's .val()oder mit dem raw- .valueAttribut abzurufen .

garst
quelle
2
Wir haben die vollständige jQuery-Bibliothek - andernfalls würde mein oben erläutertes $ -Szenario nicht funktionieren. Meine Frage war, warum das $ funktioniert, aber angle.element nicht - obwohl vollständige jQuery verfügbar ist.
irascian
1
Schließen Sie jQuery vor oder nach angle.js ein? Es sollte vor dem Winkel enthalten sein. Selektoren von id tut Arbeit mit jQuery verfügbar: jsbin.com/ohumiy/1/edit
Garen
1
Sie arbeiten in einer anderen Direktive (dh angle.element, um über id auf etwas zuzugreifen). Das Problem scheint die Art und Weise zu sein, wie dieses Steuerelement funktioniert, indem es sich an dieses Element anfügt, obwohl ich nicht verstehe, warum dasselbe jQuery-Äquivalent direkt funktionieren sollte. Wenn ich jQuery direkt verwende, muss meine Direktive ein schließendes Tag haben - das selbstschließende Tag funktioniert nicht (keine Fehler, nur ein leerer Bildschirm), was mich das Steuerelement vermuten lässt.
irascian
2
In meinem zweiten Punkt gibt es auch so etwas wie view $ value, mit dem der Inhalt eines Elements abgerufen werden kann, aber im Fall von Eingabetyp = Nummer, bei der der Benutzer "-" eingegeben hat, ist dies leer. Ich möchte, dass eine Eigenschaft wie $ rawInputValue on element den Inhalt anzeigt, BEVOR Angular eingegriffen hat, da sich das "-" noch in der Benutzeroberfläche befindet, obwohl ich in meiner Direktive keinen programmgesteuerten Zugriff darauf habe.
irascian
27
var target = document.getElementById('appBusyIndicator');

entspricht

var target = $document[0].getElementById('appBusyIndicator');
Dasun
quelle
1
Es ist besser, das zweite Beispiel zu verwenden, um sicherzustellen, dass Ihre Abhängigkeiten explizit sind und verspottet werden können, oder?
Luke
es sollte sein, aber ich denke, in Winkel 2+ verlassen wir uns einfach mehr auf Typoskript-Funktionen. Sie müssen sich nicht mehr um diese Dinge kümmern :)
Dasun
17

Ich denke nicht, dass es der richtige Weg ist, Winkel zu verwenden. Wenn es keine Framework-Methode gibt, erstellen Sie sie nicht! Dies bedeutet, dass das Framework (hier eckig) nicht auf diese Weise funktioniert.

Mit Angular sollten Sie DOM nicht wie folgt manipulieren (auf die jquery-Art), sondern einen Angular Helper wie z

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

Oder erstellen Sie Ihre eigene Direktive (Ihre eigene DOM-Komponente), um die volle Kontrolle darüber zu haben.

Übrigens können Sie hier sehen, http://caniuse.com/#search=queryselector querySelector wird gut unterstützt und kann daher sicher verwendet werden.

Thomas Decaux
quelle
2
Du hast absolut recht. In mehr als 90% der Fälle, in denen ich dachte, ich müsste das DOM manuell manipulieren, habe ich den Code überarbeitet, um die Notwendigkeit zu beseitigen, und am Ende ist der Code viel sauberer.
Stephen Chung
17

Wenn jemand schluckt, zeigt es einen Fehler, wenn wir verwenden, document.getElementById()und es wird empfohlen, zu verwenden$document.getElementById() aber er funktioniert nicht.

Verwenden -

$document[0].getElementById('id')
Kanchan
quelle
Warum injiziert Angular hier ein Array?
Peter
16

Sie können mit $ document auf Elemente zugreifen ($ document muss injiziert werden)

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

oder mit einem Winkelelement kann auf die angegebenen Elemente zugegriffen werden als:

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
quelle
1
find () - Beschränkt auf Suchvorgänge nach Tag-Namen
RJV
angle.element (document) .find ('. someClass'); funktioniert einwandfrei.
Nishant Baranwal
10

Sie sollten $ document in Ihren Controller einfügen und anstelle des Originaldokumentobjekts verwenden.

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

Wenn Sie den Zeilenumbruch des jquery-Stilelements nicht benötigen, erhalten Sie mit $ document [0] .querySelector ('# MyID') das DOM-Objekt.

Adamy
quelle
1
Sie können auch direkt auf window.document verweisen, anstatt den Aufwand für den Angulars $ document-Service zu verwenden.
MatBee
5
Natürlich können Sie, wenn Sie sich keine Sorgen darüber machen, $ document in Ihrem Unittest zu verspotten
Adamy
Ist mir nicht klar: Ich erhalte folgende Warnung: Sie sollten den $ document-Dienst anstelle des Standarddokumentobjekts verwenden, aber was bedeutet das? Irgendwelche Dokumente darüber? Vielen Dank!
Realnot
@realnot Sie können von überall in Ihrem Javascript auf das HTML-DOM-Dokumentobjekt zugreifen. w3schools.com/jsref/dom_obj_document.asp
Adamy
6

Das hat bei mir gut funktioniert.

angular.forEach(element.find('div'), function(node)
{
  if(node.id == 'someid'){
    //do something
  }
  if(node.className == 'someclass'){
    //do something
  }
});
susrut316
quelle
3
Element ist undefiniert? angular.element.find ist keine Funktion für mich, wenn ich Ihre ohne JQuery versuche.
landete
3
Bitte tu das nicht. Verwenden Sie eines der anderen Beispiele. Dies verwendet überhaupt keine Optimierungen für die Suche nach Hash-Tabellen.
MatBee
4

Verbesserung der Antwort von Kaiser:

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

Vergessen Sie nicht, $documentin Ihre Richtlinie einzufügen

Rob H.
quelle
21
Wie in der eckigen Dokumentation für element.find : erwähnt find() - Limited to lookups by tag name, funktioniert es nicht mit IDs. Sie haben auch einen zusätzlichen Abschluss ).
Paaat
3

Vielleicht bin ich zu spät hier, aber das wird funktionieren:

var target = angular.element(appBusyIndicator);

Beachten Sie, dass es keinen appBusyIndicatoreinfachen ID-Wert gibt.

Was passiert hinter den Kulissen: (vorausgesetzt, es wird auf ein Div angewendet) (ab Angular.Js Zeile Nr. 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);
  }

Wenn auf der Seite keine jQuery vorhanden ist, wird standardmäßig jqLite verwendet. Das Argument wird intern als ID verstanden und das entsprechende jQuery-Objekt wird zurückgegeben.

Vishal Anand
quelle
Ich habe dies jetzt mit Angular 1.5.8 versucht. Eine einfache ID gibt ein leeres Ergebnis zurück. angular.element("#myId")funktioniert gut.
Gosha U.
Vielleicht haben Sie jQuery auf Ihrer Seite?
Vishal Anand