back to top

I form in Vue.js

Nelle precedenti lezioni abbiamo illustrato vari esempi in cui è stata utilizzata la direttiva v-model per associare, in modo bidirezionale (two-way data binding), una proprietà dell’oggetto data di un componente al valore di un campo di input. Così facendo, ogni volta che una proprietà cambia, viene automaticamente aggiornato il valore del campo di input e viceversa.

Abbiamo visto che per i campi di testo <input type="text"> e <textarea> al posto della direttiva v-model potremmo implementare la tecnica di two-way data binding combinando la proprietà value dell’elemento e l’evento input come mostrato nel frammento di codice sottostante.

<input 
type="text" 
@input="value = $event.target.value" 
:value="value">

Grazie alla direttiva v-model possiamo infatti semplificare l’esempio precedente nel seguente modo.

<input 
type="text"  
v-model="value">

In questa lezione illustreremo come utilizzare la direttiva v-model con altri elementi di input e descriveremo altre interessanti funzionalità.

Iniziamo allora a presentare degli utili modificatori partendo da .trim che rimuove automaticamente eventuali spazi bianchi superflui dal valore di un campo di testo.

<input 
type="text"  
v-model.trim="value">

Ciò significa che se viene inserito il valore ' ciao ', la proprietà value conterrà soltanto 'ciao' dato che tutti gli spazi in eccesso vengono automaticamente eliminati.

Il modificatore .number si occupa invece di convertire automaticamente in tipo Number il valore di un campo di input che altrimenti sarebbe di tipo String. Se il valore non può essere convertito, viene restituito il valore originale.

Consideriamo infatti il seguente frammento di codice.

<input type="number" v-model="value">

Nonostante abbiamo usato l’attributo type="number", la proprietà value viene comunque convertita in una stringa.

Al contrario, grazie al modificatore .number, la proprietà value conterrà sempre dei valori di tipo Number (vale anche per i campi di input con attributo type="text").

<input type="number" v-model.number="value">

Se poi vogliamo sincronizzare il valore di un campo con la rispettiva proprietà meno frequentemente, possiamo allora usare il modificatore .lazy. In questo caso v-model userà l’evento change al posto di input (l’evento change viene emesso solo al termine della modifica dell’elemento. Per i campi di testo l’evento change si verifica solo quando l’elemento perde il focus e il suo valore è stato modificato).

<input 
type="text"  
v-model.lazy="value">

Textarea e v-model

Continuando a parlare di campi di testo, per l’elemento <textarea> non è possibile utilizzare l’interpolazione, al contrario per settare il suo valore dovremo procedere manualmente attraverso la combinazione di un evento e della proprietà value. In alternativa possiamo affidarci alla direttiva v-model come riportato sotto.

<textarea v-model="textValue" placeholder="Testo..."></textarea>

In questo modo ogni volta che si digita un nuovo carattere nella <textarea>, viene automaticamente aggiornato il valore della proprietà textValue.

Select

Ma la direttiva v-model può essere applicata anche ad altri elementi. Illustriamo allora vari esempi partendo dall’elemento <select>.

<template>
  <div>
    <select v-model="selected">
      <option disabled value="">
        Seleziona la libreria/framework preferito
      </option>
      <option>Angular</option>
      <option>React</option>
      <option>Vue</option>
    </select>
    <p>Hai selezionato: {{ selected }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selected: ''
    }   
  }
} 
</script>

Con la direttiva v-model associamo una proprietà di tipo stringa selected ad una delle opzioni disponibili per l’elemento <select>. Se per esempio selezioniamo Vue, data.selected assumerà immediatamente tale valore.

Vue consiglia di utilizzare un elemento <option disabled> con valore vuoto come opzione predefinita perché, se il valore iniziale dell’espressione associata a v-model non corrisponde a nessuna delle opzioni presenti, l’elemento <select> non mostrerà inizialmente nessuna delle opzioni disponibili. Su iOS gli utenti non potranno quindi selezionare alcuna opzione perché in questi casi non viene lanciato l’evento change.

Grazie alla direttiva v-for possiamo inoltre costruire i vari elementi <option> in maniera dinamica.

<template>
  <div>
    <select v-model="selected">
      <option disabled value="">Please select one</option>
      <option 
        v-for="option in options" 
        :key="option" 
        :value="option">{{ option }}</option>
    </select>
    <p>Hai selezionato: {{ selected }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selected: '',
      options: [
        'Angular',
        'React',
        'Vue'
      ]
    }   
  }
} 
</script>

Sempre attraverso la direttiva v-model, associata però ad un array, possiamo ottenere le opzioni selezionate in un elemento <select> con attributo multiple.

<template>
  <div>
    <select v-model="selected" multiple>
      <option 
        v-for="option in options" 
        :key="option" 
        :value="option">{{ option }}</option>
    </select>
    <p>Hai selezionato: {{ selected }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selected: [],
      options: [
        'Angular',
        'React',
        'Vue'
      ]
    }   
  }
} 
</script>

Checkbox

In modo del tutto simile a quanto visto negli esempi precedenti, possiamo usare la direttiva v-model con uno o più checkbox. Nel primo caso dovremo associare una singola proprietà, nel secondo ci affideremo ad un array di valori booleani.

<template>
  <div>
    <input type="checkbox" id="checkbox" v-model="checked">
    <label for="checkbox">{{ checked }}</label>
  </div>
</template>

<script>
export default {
  data() {
    return {
      checked: false
    }   
  }
} 
</script>

E come anticipato, in caso di valori multipli utilizzeremo un array.

<template>
  <div>
    <template v-for="option in options" >
      <input 
        type="checkbox" 
        :id="option + '-checkbox'" 
        :value="option" 
        v-model="checked" 
        :key="option">
      <label :for="option + '-checkbox'" :key="option + '-label'">
        {{ option.charAt(0).toUpperCase() + option.slice(1) }}
      </label>
    </template>
    <div>
      Hai selezionato:<br> {{ checked }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      checked: [],
      options: [
        'angular',
        'react',
        'vue'
      ]
    }   
  }
} 
</script>

https://vimeo.com/462643936

Pulsanti Radio

Per i pulsanti di tipo radio possiamo invece utilizzare la direttiva v-model come mostrato nel seguente esempio.

<template>
  <div>
    <template v-for="option in options" >
      <input 
        type="radio" 
        :id="option + '-checkbox'" 
        :value="option" 
        v-model="selected" 
        :key="option">
      <label :for="option + '-checkbox'" :key="option + '-label'">
        {{ option.charAt(0).toUpperCase() + option.slice(1) }}
      </label>
    </template>
    <div>
      Hai selezionato:<br> {{ selected }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      selected: 'vue',
      options: [
        'angular',
        'react',
        'vue'
      ]
    }   
  }
} 
</script>

Nell’esempio riportato sopra, i diversi pulsanti di tipo radio sono collegati tutti alla stessa proprietà selected che è inizializzata al valore ‘vue’. In questo modo il pulsante radio con value pari a ‘vue’ sarà quello predefinito. Ogni volta che selezioniamo un diverso pulsante, la proprietà selected assumerà di volta in volta un nuovo valore.

Esempio di form realizzato in Vue

Per concludere questa lezione vediamo come combinare quanto illustrato finora e realizzare un semplice form con diversi campi di input.

<template>
  <form @submit.prevent="onSubmit">
    <label for="name">Nome</label>
    <input type="text" id="name" v-model.trim="details.name">

    <label for="email">E-mail</label>
    <input type="email" id="email" v-model.trim="details.email">

    <label for="age">Et&agrave;</label>
    <input type="number" id="age" v-model.number="details.age">

    <select v-model="details.favoriteJsFramework">
      <option disabled value="">Seleziona JS framework preferito</option>
      <option 
        v-for="jsFramework in jsFrameworksList" 
        :key="jsFramework" 
        :value="jsFramework">
          {{ jsFramework }}
      </option>
    </select>

    <fieldset>
      <legend>Framework CSS conosciuti</legend>
      <template v-for="cssFramework in cssFrameworksList">
        <input 
          :key="cssFramework" 
          type="checkbox" 
          :id="cssFramework" 
          :value="cssFramework" 
          v-model="details.cssFrameworks">
        <label 
          :key="cssFramework + '-label'" 
          :for="cssFramework">{{ cssFramework }}</label>
      </template>
    </fieldset>

    <fieldset>
      <legend>Javascript è il tuo linguaggio preferito?</legend>

      <!-- grazie a v-bind associamo un valore booleano --> 
      <!-- a ciascun pulsante di tipo radio --> 
      <input 
        type="radio" 
        id="yes"
        :value="true" 
        v-model="details.isJSFavoriteLanguage">
      <label for="yes">S&igrave;</label>
      <input 
        type="radio" 
        id="no" 
        :value="false" 
        v-model="details.isJSFavoriteLanguage">
      <label for="no">No</label>
    </fieldset>

    <button type="submit">Invia</button>
    
  </form>
</template>

<script>
export default {
  data() {
    return {
      details: {
        name: '',
        email: '',
        age: 0,
        favoriteJsFramework: '',
        cssFrameworks: [],
        isJSFavoriteLanguage: true
      },
      jsFrameworksList: [
        'Angular',
        'React',
        'Vue'
      ],
      cssFrameworksList: [
        'Bootstrap',
        'Foundation',
        'Pure',
        'Semantic UI',
        'Tailwind'
      ]
    }   
  },
  methods: {
    onSubmit() {
      console.log(this.details);
    }
  }
} 
</script>

Nel frammento di codice riportato sopra intercettiamo l’evento submit sul form e tramite modificatore .prevent ci assicuriamo che non venga ricaricata la pagina. Nel metodo onSubmit() ci limitiamo a stampare nella console del browser l’oggetto this.$data.details.

Bisogna precisare che nell’esempio appena visto abbiamo però trascurato qualsiasi forma di gestione degli errori e di validazione dei campi che è tuttavia possibile implementare grazie alle tecniche, ai concetti e agli strumenti presentati nelle precedenti lezioni. Per semplicità non abbiamo neanche utilizzato alcuna regola CSS per definire lo stile del form.

Riepilogo

In questa lezione abbiamo illustrato come creare dei form in Vue.js e abbiamo visto come utilizzare la direttiva v-model con i diversi tipi di elementi <input>. Nella prossima lezione vedremo come definire ed usare delle direttive personalizzate.

Pubblicitร