[Javascript] Ruotare freccia su clic del mouse

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
Ciao ragazzi, come da titolo mi servirebbe unamano per far ruotare una freccia tramite JavaScript che devo ancora imparare.
La freccia è un'icona di Font Awsome e questo è il codice che ho provato a scrivere...e che ovviamente non funziona :p:

HTML:
<i class="fas fa-angle-down" id="icon"></i>
Codice:
var arrow = document.getElementById('icon');

arrow.onclick = function() {
arrow.style.transform = 'rotateX(180deg);
}
Se possibile vorrei far in modo che al primo clic ruoti di 180° e ricliccandola torni in posizione di partenza (rivolta verso il basso).

Grazie!
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Ciao, fai attenzione, nel tuo script manca un apice di chiusura della stringa applicata alla proprietà transform.

Ciò che vuoi fare è possibile risolverlo in vari modi. Parliamo di una sorta di effetto cosiddetto "toggle", in sostanza un elemento che cambia e ripristina il suo stato in modo alternato ad ogni click. In genere per sistemi del genere si utilizza una variabile che assuma il valore 0 o 1 a seconda dello stato in cui si trova l'elemento. A quel punto basterà una semplice condizione per verificare in quale stato si trova l'elemento e applicare quindi lo stato opposto.

Nel tuo caso, partendo dal tuo semplice esempio, si potrebbe risolvere anche senza ulteriori variabili ma verificando semplicemente il valore di quella proprietà (transform) che stai andando a modificare. Nello specifico vai a verificare, attraverso una condizione, se tale proprietà è una stringa vuota oppure è stata valorizzata e, di conseguenza, vai ad applicargli il valore opposto.

Con una condizione if/else potrebbe essere impostato in questo modo:
Codice:
if (arrow.style.transform == "") {              // se transform è una stringa vuota (quindi lo stato iniziale dell'icona)
   arrow.style.transform = "rotateX(180deg)";   // applico la rotazione
} else {                                        // altrimenti
   arrow.style.transform = "";                  // azzero nuovamente transform (per cui l'icona torna allo stato iniziale)
}
In alternativa (in modo concettualmente uguale) è possibile risolvere con un operatore ternario ottenendo una sintassi nettamente più stringata:
Codice:
arrow.style.transform = arrow.style.transform ? "" : "rotateX(180deg)";
 
Ultima modifica:

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
Ciao WmbertSea, grazie per aver risposto. Ho provato ad usare il codice postato da te ma c'è qualcosa che non va, non funziona:

HTML:
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
  </head>

  <body>

    <i class="far fa-angry fa-7x" id="icon"></i>

  </body>

</html>
Codice:
<script>
    var arrow = document.getElementById('icon');

    arrow.onclick = function() {
        if (arrow.style.transform = "") {
            arrow.style.transform = "rotateX(180deg)";
        }
        else {
            arrow.style.transform = "";
        }
    }
</script>
Non capisco dove sbaglio :(
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Ciao, non vedo dove hai incluso lo script sul documento html. Chiaramente deve essere eseguito dopo che l'elemento icon è stato creato sulla pagina perché possa essere rilevato con getElementById. Dove è incluso quello script?
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Si trova prima della chiusura del tag <body>
Bene, è corretto allora.

qui l'ho messo separato altrimenti chi li vuol sentre i Mod
No, che c'entra. Se il tuo script sta dentro il codice html non credo sia un problema postarlo tutto assieme. Anzi, se lo separi può creare confusione nella comprensione del problema, come in questo caso.

Ad ogni modo è stato un errore mio; avevo riportato il codice senza provarlo e non mi sono accorto che avevo fatto un errore da niubbo :p... chiaramente nella condizione va messo l'operatore di confronto (==) e non quello di assegnazione (=).

Ho corretto il codice del mio precedente post. Riprovalo e vedi se funziona.
 
  • Like
Reactions: iTonto

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
Perfetto, ora funziona. Grazie! :)

Se non ti dispiace avrei una domanda da farti: quest'icona dovrei usarla più volte, posso usarla con lo stesso id per ogni icona o dovrei assegnare una classe ad ogni icona? Non vorrei che poi al clic si girino tutte insieme...
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Se non ti dispiace avrei una domanda da farti
Nessun problema.
quest'icona dovrei usarla più volte, posso usarla con lo stesso id per ogni icona
Assolutamente no, gli id devono essere univoci all'interno di uno stesso documento, per questo esistono le classi che invece possono essere applicate a più elementi. Sono le basi della programmazione web, non mi dilungo su questo punto ma tu puoi approfondire con qualche semplice ricerca sul web, ad esempio: differenza tra class e id

o dovrei assegnare una classe ad ogni icona? Non vorrei che poi al clic si girino tutte insieme...
Sì, puoi appunto usare una classe da applicare ad ogni elemento a cui vuoi associare quell'effetto. Lo script sarà però leggermente più complesso. Se utilizzi jQuery la cosa risulta tutto sommato semplice, mentre in puro JavaScript ti servirà selezionare gli elementi con tale classe, ad esempio usando il metodo getElementsByClassName con cui ottieni un oggetto NodeList, quindi ciclare gli elementi di tale oggetto per poter applicare a ciascuno il tuo evento onclick.

Sulla guida del metodo getElementsByClassName trovi un esempio di un semplice ciclo a cui è applicata una proprietà css per ciascuno degli elementi di una specifica classe. Dovrai fare più o meno allo stesso modo per applicare l'evento e, a quel punto, dentro la funzione definita per l'evento puoi usare la keyword this che ti servirà per ottenere il riferimento al relativo elemento che sta richiamando quel tale evento.

Per il momento fai magari qualche prova e posta ciò che riesci ad ottenere.
 

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
HTML:
<!doctype html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Untitled Document</title>
    <head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
  </head>
   
    <style>
        #icon {
            transition: transform 0.5s;
        }
    </style>
  <body>

    <i class="fas fa-angle-down fa-7x icon"></i>
    <i class="fas fa-angle-down fa-7x icon"></i>
    <i class="fas fa-angle-down fa-7x icon"></i>
   
    <script>
        function myfunction() {
            var x = document.getElementsByClassName('icon');
            var i;
            for (i = 0; i < x.length; i++) {
                if (x[i].style.transform == '') {
                    x[i].style.transform = 'rotate(180deg)';
                }
                else {
                    x[i].style.transform = '';
                }
            }
        }
       
        onclick = myfunction();
    </script>
  </body>

</html>
Ehm...credo ci sia qualcosa che non va :D
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Ad occhio vedo che stai applicando la proprietà ma io ti ho indicato questo:
trovi un esempio di un semplice ciclo a cui è applicata una proprietà css [...] Dovrai fare più o meno allo stesso modo per applicare l'evento e... dentro la funzione... usare la keyword this
Il modo è simile ma nel ciclo, per ciascun elemento, devi assegnare l'evento onclick, non la proprietà.

In altre parole ciò che hai fatto inizialmente per l'elemento arrow (questo):
Codice:
var arrow = document.getElementById('icon');
arrow.onclick = function() {
... va rielaborato in modo che il metodo/evento onclick sia applicato ad x[i] che sta dentro il ciclo.

Fai qualche altro tentativo così correggiamo il tiro :)
 
Ultima modifica:

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
HTML:
<i class="fas fa-angle-down fa-7x icon"></i>
    <i class="fas fa-angle-down fa-7x icon"></i>
    <i class="fas fa-angle-down fa-7x icon"></i>
    
    <script>
        var arrow = document.getElementsByClassName('icon');
        
        arrow.onclick = function() {
            var arrow;
            var = i;
            for (i = 0; i < arrow.length; i++) {
                if (arrow.style.transform = '') {
                    this.style.transform = 'rotate(180deg)';
                }
                else {
                    this.style.transform = '';
                }
            }
        }
    </script>
Un suggerimento in più? :(
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Il metodo getElementsByClassName restituisce un oggetto NodeList, cioè una collezione di elementi DOM. In sostanza è simile ad un array contenente tutti gli elementi trovati con quel metodo, una cosa del tipo:
Codice:
[elemento1, elemento2, elementoN]
Se tu fai:
Codice:
var arrow = document.getElementsByClassName('icon');
stai dicendo che arrow è appunto un oggetto NodeList
Quindi ottieni una cosa del genere:
Codice:
var arrow = [elemento1, elemento2, elementoN]
Cosa significa questo? Che un oggetto NodeList non possiede onclick tra i suoi metodi. Quel metodo infatti devi applicarlo agli elementi di quell'oggetto, non all'oggetto stesso.

Questo quindi non ha senso:
Codice:
var arrow = document.getElementsByClassName('icon');
arrow.onclick = function() { ...
Dovrai invece eseguire un ciclo per "recuperare" i singoli elementi di quell'oggetto e, a quel punto, applicare il metodo onclick a tali elementi.

Sai eseguire un ciclo per gli elementi di un array?
Il procedimento è uguale.
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Giusto. La variabile i del ciclo dovrai poi usarla come indice per "recuperare" gli elementi di quell'oggetto NodeList (che hai istanziato con la tua variabile arrow).

Quindi, come fai ad accedere ai singoli elementi di quell'oggetto?

Nell'esempio di quella guida viene usato x, e per ciascun elemento viene impostata una proprietà del relativo oggetto style. La tua variabile invece è arrow e per ciascuno dei suoi elementi devi impostare il relativo metodo onclick.

Tieni conto che queste ultime sono delle nozioni base di programmazione che vanno comunque oltre l'argomento in discussione. Capisco il tuo intento di voler imparare ma è chiaro che non ti si può fare una lezione di programmazione da zero per il tipo di discussione che hai aperto.

Senza alcuna offesa, sia chiaro, ma se l'intento è quello di imparare, e hai bisogno di imparare dei concetti base, dovresti iniziare da delle guide di base e nel caso aprire delle discussioni specifiche per ognuno di tali argomenti che intendi approfondire. Se invece ti serve giusto uno script bello e pronto, a me costa poco postartelo, basta dirlo, ma ovviamente un approccio di questo genere sarebbe poco produttivo per te.

Vedi tu che fare e fai sapere.
 

iTonto

Utente Attivo
8 Feb 2018
99
1
18
www.fiverr.com
Ma no che offesa figurati, sei fin troppo paziente altri non avrebbero continuato a rispondermi. Hai ragione, ovviamente è impensabile fare lezioni di programmazione via forum però su questa cosa vorrei riuscire da solo...con il tuo aiuto magari :p, è più una questione di principio che altro. Poi mi metteerò a studiare come si deve.

Quindi, ricapitombolando:

Codice:
<script>
var arrow = document.getElementsByClassName('icon');

for (i = 0; i < arrow.lenght; i++) {
if (arrow[i].style.transform == '') {
arrow[i].onclick.this.style.transform = 'rotate(180deg)';
}
else {
arrow[i].onclick.this.style.transform = '';
}
}
</script>
Può andare?
 

WmbertSea

Utente Attivo
28 Nov 2014
161
21
28
Con il ciclo ci siamo e anche su questo passaggio:
Codice:
arrow[i].onclick
ma per il resto non ci siamo. Hai fatto un po' un miscuglio delle altre cose, ovviamente non può funzionare.
Come già detto, ti mancano chiaramente quelle nozioni principali sulla programmazione orientata agli oggetti per poter comprendere a livello concettuale come poter impostare questa roba. Inutile andare a tentoni, per me diventa controproducente.

Ripeto, dovresti iniziare quanto prima a consultare qualche guida di base. In questo stesso portale ci sono vari articoli, tutorial e delle valide guide, vedi ad esempio questa guida completa di JavaScript. Nel limite del possibile cerco di riepilogare alcuni punti fondamentali che ti aiuteranno (spero) a capire i meccanismi per poter approntare un qualsivoglia script come quelli che stai cercando di impostare in questa discussione.

Qui le nozioni essenziali riguardo la programmazione ad oggetti in JavaScript (clicca sui link per approfondire i vari argomenti):

- JavaScript è un linguaggio OOP, gli oggetti sono la cosa fondamentale. La maggior parte delle cose in JavaScript sono oggetti.

- Ogni oggetto è un'istanza di una classe. La classe non è altro che il modello astratto su cui sono definite le caratteristiche e le funzionalità dei relativi oggetti (istanze di tale classe).

- Un oggetto è sostanzialmente un recipiente che può contenere proprietà e metodi. Tutti gli elementi del DOM (cioè gli elementi relativi ai nodi del documento HTML) in JavaScript sono rappresentati come degli oggetti, ognuno dei quali possiede svariate proprietà e metodi.

- Una proprietà di un oggetto non è altro che una variabile definita per tale oggetto, la quale può contenere dei dati di qualsiasi tipo, ad esempio una stringa testuale, un valore numerico, un valore booleano, un array, ecc. Una proprietà può inoltre essere a sua volta un oggetto che potrà quindi contenere proprietà e metodi.

- Un metodo di un oggetto è semplicemente una funzione definita per tale oggetto, cioè un blocco di codice incaricato a compiere delle azioni quando lo si richiama. In JavaScript la funzione stessa è un oggetto dotato anch'esso di proprietà e metodi.

- Un metodo (proprio come una funzione) tra le sue mansioni può avere quella di restituire qualcosa (che può essere un qualsiasi tipo di dato, anche un oggetto).

- Un metodo è definito come gestore di evento (in inglese "event handler" o semplicemente "handler" o "listener") quando questo viene eseguito al verificarsi di un determinato evento. Per gli elementi del DOM possono verificarsi svariati tipi di eventi. Si ha, ad esempio, l'evento click, load, keypress e molti altri, e per ognuno di questi esiste un corrispettivo gestore (onclick, onload, onkeypress, ecc.). Ogni metodo "gestore di evento" è quindi una funzione definita su un oggetto, la quale viene eseguita quando si verifica un determinato evento.

Una piccola nota: comunemente si utilizza il termine "evento" per riferirsi in genere al "gestore" di tale evento. Ad esempio quando si trova scritto "l'evento onclick" chiaramente è inteso che ci si sta riferendo al "gestore onclick" (relativo all'evento click).

- In JavaScript esistono degli oggetti nativi tra cui "window" e "document".

- L'oggetto window è quello principale che rappresenta l'intera finestra in cui è caricata la pagina HTML, ed è il livello base (globale) dal quale "parte" l'esecuzione dello script.

- L'oggetto document è in realtà una proprietà di window che rappresenta il nodo principale del contenuto HTML caricato nella pagina. Questo oggetto possiede varie proprietà e metodi utili per accedere e manipolare qualsiasi elemento del DOM presente nella pagina.

- Ultimo punto importante (per il momento) è il concetto di scope (cioè il contesto di visibilità delle variabili che sono definite ed accessibili in un particolare punto dentro lo script) e l'uso della parola chiave this (un oggetto che fa riferimento all'elemento che definisce lo scope stesso, cioè il contesto corrente su cui è eseguito un qualsiasi blocco di script).

---

Queste sono le basi da avere bene a mente quando si programma in JavaScript. Applicandole agli esempi in questione possiamo constatare alcune cose:

- document è un oggetto che ha proprietà e metodi

- Un metodo di document è getElementsByClassName(). Tale metodo seleziona una serie di elementi del DOM e restituisce un oggetto di tipo NodeList,

- Un oggetto NodeList è una collezione di nodi HTML (cioè elementi del DOM). E' possibile "navigare" un tale oggetto così come lo si fa per un array.

- Un oggetto NodeList ha delle proprietà e dei metodi. Una sua proprietà ad esempio è "lenght" che (così come un array) indica il numero di membri (nodi) presenti nell'oggetto stesso. Per questo nel tuo script (in cui definisci arrow come un oggetto NodeList) puoi scrivere arrow.lenght e usare tale valore per limitare il numero di iterazioni del tuo ciclo. Il ciclo si ripete infatti per il numero di elementi contenuti in arrow. Inoltre (proprio come un array) puoi usare un indice per far riferimento a ciascuno dei suoi elementi, per questo puoi scrivere arrow[i], dove i è la variabile numerica che viene incrementata nel ciclo.

- Un oggetto NodeList ha dei metodi utili per "navigare" gli elementi al suo interno. Non possiede un evento "click" e relativo metodo "onclick". Un oggetto NodeList infatti non è, di per sé, un elemento cliccabile come lo sono invece gli elementi del DOM. Per ogni elemento del DOM è possibile infatti impostare un gestore "onclick". Per questo nel tuo script non ha senso scrivere arrow.onclick = function() { ... dal momento che arrow è un oggetto NodeList

- Il metodo "onclick" lo devi definire invece per gli elementi contenuti nell'oggetto NodeList. Per questo avrebbe senso scrivere, dentro il ciclo, una cosa come arrow[i].onclick = function() { ... , cosa che non hai fatto.

- Ancora, il metodo "onclick" deve essere definito come funzione (che appunto gestisce l'evento "click"), non ha quindi delle sue proprietà. Per questo non ha senso scrivere arrow[i].onclick.this.style.transform...

- Quindi, ogni elemento dell'oggetto NodeList rappresenta il relativo elemento selezionato del DOM. Ognuno dei quali non è altro che un oggetto che possiede proprietà e metodi.

- Ogni elemento del DOM possiede una proprietà style che a sua volta è un oggetto di tipo CSSStyleDeclaration il quale possiede altre svariate proprietà relative ai corrispettivi attributi CSS. Queste sono principalmente proprietà di tipo stringa con cui è possibile impostare ogni corrispettivo attributo CSS relativo all'elemento in questione. Per questo nell'esempio della guida è scritto x[i].style.transform = 'rotate(180deg)'; dove x[i] rappresenta ogni singolo elemento DOM appartenente all'oggetto x (che appunto è un NodeList). Ma nel tuo script quel CSS dovrai impostarlo, non tanto appena è eseguito il ciclo, ma bensì dentro il gestore "onclick".

- Dentro la funzione definita per onclick, puoi usare l'oggetto this come identificatore dell'elemento da cui è scaturito l'evento click (quindi l'elemento da cui è stato invocato il metodo gestore onclick). Per cui nel tuo script potrai ad esempio scrivere, dentro tale funzione, this.style.transform = ...

---

Questo è quanto. E' un bignami della programmazione JavaScript ma senza dubbio bisogna studiare ed approfondire i vari punti prima di iniziare a scrivere con criterio qualche riga di script. Non ci sono troppe alternative.

Di più non posso contribuire, spero di aver chiarito qualcosa in più per il momento.
Fai qualche prova cercando di seguire tali indicazioni, cercando di fare tuoi questi concetti.

Fai sapere i tuoi eventuali progressi.
Buon proseguimento.
 
Ultima modifica:
  • Like
Reactions: iTonto