Skip to content

6. proyecto [vuejs-04]: directivas [v-model, v-bind], atributos calculados, formulario de entrada

La estructura del proyecto [vuejs-04] es la siguiente:

Image

6.1. El script principal [main.js]

Es el mismo que en el ejemplo anterior.

6.2. El componente principal [App]

El código de [App.vue] es el siguiente:


<template>
  <b-container>
    <b-card>
      <!-- mensaje de presentación -->
      <b-row>
        <b-col cols="8">
          <b-alert show variant="success" align="center">
            <h4>[vuejs-04] : directives [v-model, v-bind], attributs calculés, formulaire de saisie</h4>
          </b-alert>
        </b-col>
      </b-row>
      <Form />
    </b-card>
  </b-container>
</template>


<script>
  import Form from "./components/Form.vue";

  export default {
    name: "app",
    components: {
      Form
    }
  };
</script>

El componente [App.vue] utiliza el nuevo componente [Form] (líneas 12, 19, 24).

6.3. El componente [Form]

El código del componente [Form] es el siguiente:


<template>
  <div>
    <!-- formulario -->
    <b-form>
      <!-- elementos del formulario -->
      <b-row>
        <b-col cols="4">
          <b-card bg-variant="light">
            <b-form-group label="Nombre d'enfants à charge" label-for="enfants">
              <b-input type="text"
                       id="enfants"
                       placeholder="Indiquez votre nombre d'enfants"
                       v-model="enfants"
                       v-bind:state="enfantsValide" />
              <b-form-invalid-feedback :state="enfantsValide">Vous devez saisir un nombre positif ou nul</b-form-invalid-feedback>
            </b-form-group>
            <!-- botón -->
            <b-button variant="primary" :disabled="formInvalide" @click="doSomething">Valider</b-button>
          </b-card>
        </b-col>
      </b-row>
    </b-form>
    <b-row class="mt-3">
      <b-col cols="4">
        <b-alert show variant="warning" align="center">
          <h4>enfants= {{enfants}}</h4>
        </b-alert>
      </b-col>
    </b-row>
  </div>
</template>

<!-- script -->
<script>
  export default {
    // nombre
    name: "Form",
    // atributos estáticos del componente
    data() {
      return {
        // número de hijos
        enfants: ""
      };
    },

    // atributos calculados
    computed: {
      // atributo [formInvalide]
      formInvalide() {
        return !this.enfantsValide;
      },
      // atributo [enfantsInvalide]
      enfantsValide() {
        return Boolean(this.enfants.match(/^\s*\d+\s*$/));
      }
    },
    // métodos
    methods: {
      doSomething() {
        // el número de hijos se conoce cuando se realiza la validación
        alert("Nombre d'enfants : " + this.enfants);
      }
    }
  };
</script>

Representación visual

Image

Image

Comentarios

  • líneas 4-32: la etiqueta <b-form> introduce un formulario Bootstrap;
  • línea 6: la etiqueta <b-row> introduce una fila en el formulario;
  • línea 7: la etiqueta <b-col cols=’4’> introduce una columna que ocupa 4 columnas de Bootstrap;
  • línea 8: la etiqueta <b-card> [6] introduce una tarjeta Bootstrap, un área enmarcada por un borde;
  • línea 9: la etiqueta <b-form-group> introduce un grupo de elementos del formulario vinculados entre sí. Aquí, un texto (atributo [label]) [1] está vinculado a un campo de entrada (atributo [label-for]). El valor de [label-for] es el valor del campo [id], línea 12, del campo de entrada;
  • líneas 10-14: la etiqueta <b-input> [2] introduce un campo de entrada:
    • línea 10: [type=’text’] indica que se puede escribir texto en el campo de entrada. Se podría haber escrito [type=’number’] con restricciones [min=’val1’ max=’val2’ step=’val3’], ya que se espera un número de elementos secundarios. Se ha puesto [type=’text’] para mostrar cómo verificar la validez de una entrada;
    • línea 12: el atributo [placeholder] [3] establece el mensaje que se muestra en el campo de entrada mientras el usuario no haya introducido nada;
    • línea 13: la directiva [v-model] asocia, de forma bidireccional, el valor introducido con el atributo [enfants], línea 42, del componente:
      • cuando cambia el valor introducido, también cambia el valor del atributo [enfants];
      • cuando cambia el valor del atributo [enfants], entonces el valor introducido también cambia, es decir, cambia el contenido de [2];
      • lo importante es comprender que, gracias al mecanismo anterior, cuando el usuario hace clic en el botón [Valider] [5], el atributo [enfants] de la línea 42 toma como valor el valor introducido en [2];
    • línea 14: la directiva [v-bind] establece un enlace entre, por un lado, un atributo de la etiqueta <b-input>, en este caso el atributo [state], y un atributo del componente, en este caso [enfantsValide], línea 53. El atributo [enfantsValide] es especial en el sentido de que es una función que devuelve el valor del atributo. A este tipo de atributo se le denomina «atributo calculado». Los atributos calculados se encuentran en la propiedad [computed], línea 47, del componente. Los atributos calculados se utilizan de la misma manera que los atributos estáticos de la función [data]: en la línea 14 no se escribe [v-bind:state=’enfantsValide()’], sino [v-bind:state=’enfantsValide’], sin paréntesis. Además, al leer [template], no se puede distinguir un atributo calculado de un atributo estático. Para ello, hay que consultar el código del script del componente;
    • línea 14: el atributo [state] determinará el estado válido/inválido del valor introducido: si [enfantsValide] devuelve el valor [true], el valor introducido se considera válido; en caso contrario, se considera inválido. La captura de pantalla anterior muestra el componente [b-input] cuando la función [enfantsValide] devuelve el valor [false];
    • línea 15: la etiqueta <b-form-invalid-feedback> [4] permite mostrar un mensaje cuando la entrada en [2] no es válida. Su atributo [:state=’enfantsValide’] es idéntico al atributo [v-bind:state=’enfantsValide’] de la línea 14. Se puede omitir la directiva [v-bind], pero hay que mantener el signo [:]. Por lo tanto, el mensaje de error aparece cuando el atributo [enfantsValide] es igual a [false];
    • línea 16: fin del grupo de elementos <b-group>;
    • línea 18: el botón [5] que permitirá validar la entrada:
      • será de color azul [variant=’primary’];
      • [:disabled="formInvalide"]: el atributo [disabled] permite validar o invalidar el botón. Este atributo está vinculado (v-bind) al atributo calculado [formInvalide] de la línea 49;
      • [@click="doSomething"]: cuando el usuario haga clic en el botón, se ejecutará el método [doSomething], línea 59;
    • líneas 19-22: cierre de las diferentes etiquetas abiertas;
    • líneas 23-29: una nueva línea en [template]. [class=’mt-3’] significa [margin (m) top (t) égale à 3 spacers]. [spacer] es una medida de espaciado de Bootstrap. Esta clase genera el espaciado [8] en la captura de pantalla anterior. Sin esta clase, el área [7] queda pegada al área [1-6];
    • línea 24: una columna que ocupa 4 columnas de Bootstrap;
    • líneas 25-27: una alerta [warning] que muestra el valor del atributo estático [enfants] (línea 42). Dado que este atributo tiene un enlace bidireccional con el campo de entrada, en cuanto el usuario lo modifica, el valor mostrado en la alerta también cambia;
    • líneas 34-65: el código jS del componente;
    • línea 42: el único atributo estático del componente;
    • líneas 47-56: los atributos calculados del componente;
    • líneas 53-55: la entrada se considera válida si es un número entero positivo, eventualmente precedido o seguido de «espacios»;
    • líneas 49-51: el formulario se considera válido si la entrada del número de hijos es válida. En general, un formulario tiene varias entradas y se considera válido si todas ellas son válidas;
    • líneas 58-63: los métodos del componente que reaccionan a sus eventos. Aquí solo hay un evento: el [click] en el botón. Nos limitamos a mostrar el valor introducido para demostrar que tenemos acceso a él;

6.4. Ejecución del proyecto

Modificamos el archivo [package.json] y ejecutamos el proyecto:

Image