selettore angular.element vs document.getElementById o jQuery con controllo spin (occupato)


157

Sto usando la versione "Angularized" del controllo Spin, come documentato qui: http://blog.xvitcoder.com/adding-a-weel-progress-indicator-to-your-angularjs-application/

Una delle cose che non mi piacciono della soluzione mostrata è l'uso di jQuery nel servizio che collega efficacemente il controllo di rotazione all'elemento DOM. Preferirei usare costrutti angolari per accedere all'elemento. Vorrei anche evitare di "codificare" l'id dell'elemento a cui lo spinner deve collegarsi all'interno del servizio e utilizzare invece una direttiva che imposta l'id nel servizio (singleton) in modo che altri utenti del servizio o il servizio stesso non ha bisogno di saperlo.

Sto lottando con ciò che angular.element ci dà rispetto a quale document.getElementById sullo stesso elemento ID ci dà. per esempio. Questo funziona:

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

Nessuno di questi fa:

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

Sto chiaramente facendo qualcosa che dovrebbe essere abbastanza evidente! Qualcuno può aiutare?

Supponendo di riuscire a far funzionare quanto sopra, ho un problema simile con il tentativo di sostituire l'accesso jQuery all'elemento: ad esempio, $(target).fadeIn('fast'); funziona angular.element('#appBusyIndicator').fadeIn('fast')o angular.element('appBusyIndicator').fadeIn('fast')no

Qualcuno può indicarmi un buon esempio di documentazione che chiarisce l'uso di un "elemento" angolare rispetto all'elemento DOM? Ovviamente Angolare "avvolge" l'elemento con le sue proprietà, metodi ecc. Ma spesso è difficile ottenere il valore originale. Ad esempio se ho un <input type='number'>campo e voglio accedere ai contenuti originali che sono visibili nell'interfaccia utente quando l'utente digita "-" (senza virgolette) non ottengo nulla, presumibilmente perché "type = number" significa che Angular sta rifiutando l'input anche se è visibile nell'interfaccia utente e voglio vederlo in modo da poterlo testare e cancellarlo.

Tutti i suggerimenti / risposte apprezzati.

Grazie.


5
angular.element è un oggetto jQlite o un oggetto jQuery se si sta caricando jQuery.
Neil,

Risposte:


226

Si può lavorare così:

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

Si avvolge la chiamata Document.querySelector()Javascript nativa nella angular.element()chiamata. Quindi ottieni sempre l'elemento in un oggetto jqLite o jQuery , a seconda che jQuerysia disponibile o caricato o meno .

Documentazione ufficiale per angular.element:

Se jQuery è disponibile, angular.elementè un alias per la jQueryfunzione. Se jQuery non è disponibile, angular.elementdelega al sottoinsieme incorporato di Angular dijQuery quello chiamato "jQuery lite" o jqLite .

Tutti i riferimenti agli elementi in Angularsono sempre racchiusi con jQuery o jqLite(come l'argomento element in una compilazione di direttive o in una funzione di collegamento). Non sono mai DOMriferimenti grezzi .

Nel caso ti chiedessi perché utilizzarlo document.querySelector(), leggi questa risposta .


41
Qual è il motivo per cui si preferisce document.querySelector ('# ...') al semplice utilizzo di document.getElementById ()?
Kato,

4
Puoi anche farlo su un elemento angolare: var elDivParent = angular.element (elem [0] .querySelector ('# an-id')); elem essendo un elemento angolare. In questo modo puoi cercare all'interno di un elemento. Utile per i test unitari.
unludo,

4
@Kato Maggiori informazioni in questa risposta . Spero che aiuti.
Kaiser

lavorando con API di Google Maps, e questo ha funzionato: var autocomplete = new google.maps.places.Autocomplete( $document[0].querySelector('#address'), { types: ['geocode'], componentRestrictions: {country: 'us'} } );. Grazie per il suggerimento @kaiser. Per qualche ragione, le mappe API si sono lamentate del fatto che ciò che ho passato nel primo parametro non era un input quando l'ho usato angular.element(document.querySelector('#address')), ma tutto va bene così.
nymo il

49

Dovresti leggere i documenti dell'elemento angolare se non l'hai ancora fatto, quindi puoi capire cosa è supportato da jqLite e cosa non -jqlite è un sottoinsieme di jquery incorporato in angolare.

Questi selettori non funzioneranno solo con jqLite, poiché i selettori per ID non sono supportati.

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

Quindi, sia:

  • usi jqLite da solo, più limitato di jquery, ma abbastanza nella maggior parte delle situazioni.
  • oppure includi l'intera libreria jQuery nella tua app e la usi come una normale jquery, nei punti in cui hai davvero bisogno di jquery.

Modifica: Nota che jQuery deve essere caricato prima di angularJS per avere la precedenza su jqLite:

Real jQuery ha sempre la precedenza su jqLite, a condizione che sia stato caricato prima dell'attivazione dell'evento DOMContentLoaded.

Edit2: ho perso la seconda parte della domanda prima:

Il problema con <input type="number">, penso che non sia un problema angolare, è il comportamento previsto dell'elemento numerico html5 nativo .

Non restituirà un valore non numerico anche se si tenta di recuperarlo con jquery .val()o con l' .valueattributo raw .


2
Abbiamo la libreria jQuery completa, altrimenti il ​​mio $ scenario spiegato sopra non funzionerebbe. La mia domanda era: perché $ funziona ma angular.element non funziona, anche se è disponibile jQuery completo.
irasciano,

1
Includete jQuery prima o dopo angular.js? Dovrebbe essere incluso prima dell'angolo. I selettori di id fanno lavoro con jQuery disponibili: jsbin.com/ohumiy/1/edit
Garst

1
Stanno lavorando in un'altra direttiva (ovvero angular.element per accedere a qualcosa tramite ID). Il problema sembra essere il modo in cui funziona questo controllo collegandosi a quell'elemento, anche se non capisco perché lo stesso equivalente jQuery dovrebbe funzionare direttamente. L'uso diretto di jQuery nella mia direttiva DEVE avere un tag di chiusura - il tag di chiusura automatica non funziona (nessun errore, solo uno schermo vuoto) che mi fa sospettare il controllo.
irasciano,

2
Sul mio secondo punto c'è anche qualcosa come view $ value che può essere usato per recuperare il contenuto di un elemento ma nel caso di input type = number dove l'utente ha inserito "-" questo è vuoto. Voglio una proprietà simile a $ rawInputValue sull'elemento per vedere il contenuto PRIMA che Angular sia intervenuto perché il "-" è ancora nell'interfaccia utente anche se non ho accesso ad esso programmaticamente nella mia direttiva.
irasciano,

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

è uguale a

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

1
È meglio usare il secondo esempio per assicurarsi che le tue dipendenze siano esplicite e possano essere derise, giusto?
Luca,

dovrebbe essere, ma suppongo che in Angular 2+ ci basiamo solo su altre caratteristiche dattiloscritte. Non devi più preoccuparti di queste cose :)
Dasun,

17

Non penso sia il modo giusto di usare l'angolare. Se non esiste un metodo framework, non crearlo! Ciò significa che il framework (qui angolare) non funziona in questo modo.

Con angular non dovresti manipolare DOM in questo modo (il modo jquery), ma usare un helper angolare come

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

O crea la tua direttiva (il tuo componente DOM) per avere il pieno controllo su di essa.

A proposito, puoi vedere qui http://caniuse.com/#search=queryselector querySelector è ben supportato e quindi può essere utilizzato in sicurezza.


2
Hai assolutamente ragione. Oltre il 90% dei casi che pensavo di dover manipolare manualmente il DOM, ho finito con il refactoring del codice per rimuovere il bisogno e alla fine il codice è molto più pulito.
Stephen Chung,

17

Se qualcuno usa gulp, mostra un errore se lo usiamo document.getElementById()e suggerisce di usarlo $document.getElementById()ma non funziona.

Uso -

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

Perché angolare sta iniettando un array qui?
Peter,

16

Puoi accedere agli elementi usando $ document ($ document deve essere iniettato)

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

o con l'elemento angolare, è possibile accedere agli elementi specificati come:

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 () - Limitato alle ricerche per nome tag
RJV

angular.element (documento) .find (' someClass.); funziona perfettamente bene.
Nishant Baranwal,

10

Dovresti iniettare $ document nel tuo controller e usarlo al posto dell'oggetto document originale.

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

Se non hai bisogno di avvolgere l'elemento in stile jquery, $ document [0] .querySelector ('# MyID') ti darà l'oggetto DOM.


1
Puoi anche fare riferimento direttamente a window.document invece di utilizzare il sovraccarico del servizio documenti Angulars $.
MatBee,

5
Certo che puoi se non ti preoccupi di deridere $ document nel tuo unittest
Adamy

Non mi è chiaro: ottengo questo avviso: dovresti usare il servizio $ document invece dell'oggetto document predefinito, ma cosa significa? Qualche documentazione a riguardo? Grazie!
Realnot

@realnot puoi accedere all'oggetto documento DOM HTML HTML da qualsiasi punto del tuo javascript. w3schools.com/jsref/dom_obj_document.asp
Adamy

6

Questo ha funzionato bene per me.

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

3
elemento non definito? angular.element.find non è una funzione per me provare la tua senza JQuery.
sbarcò

3
Per favore, non farlo. Usa uno degli altri esempi. Questo non utilizza affatto ottimizzazioni per la ricerca della tabella hash.
MatBee,

4

Miglioramento della risposta di Kaiser:

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

Non dimenticare di iniettare $documentnella tua direttiva


21
Come accennato nella documentazione angolare per element.find : find() - Limited to lookups by tag name, non funziona su ids. Inoltre hai una chiusura extra ).
Paaat,

3

Forse sono troppo tardi qui ma questo funzionerà:

var target = angular.element(appBusyIndicator);

Si noti che non esiste appBusyIndicator, è un semplice valore ID.

Cosa sta succedendo dietro le quinte: (supponendo che sia applicato su un div) (preso dalla linea angular.js n. 2769 in poi ...)

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

Di default se non c'è jQuery sulla pagina, verrà usato jqLite. L'argomento viene interpretato internamente come id e viene restituito l'oggetto jQuery corrispondente.


Ho provato questo adesso con Angular 1.5.8. Un ID semplice restituisce un risultato vuoto. angular.element("#myId")funziona bene.
Gosha U.

forse hai jQuery sulla tua pagina?
Vishal Anand,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.