Znajdziesz nas na:
27.06.23 3 min czytania Technologia

Jak tworzyć formularze z Storyblok i Vue.js/Nuxt?

How to create dynamic forms with Storyblok and Vue.js/Nuxt? - blog post banner

W dzisiejszych czasach tworzenie interaktywnych i dynamicznych formularzy jest niezwykle istotne dla wielu projektów internetowych. Odpowiednie narzędzia pozwalają na stworzenie funkcjonalnych, łatwych w obsłudze i atrakcyjnych dla użytkowników formularzy. W tym artykule skupimy się na wykorzystaniu Storyblok wraz z frame-workiem Nuxt, aby stworzyć dynamiczne formularze w prosty i efektywny sposób. Przedstawimy możliwości, jakie daje nam ta kombinacja, oraz kroki potrzebne do stworzenia formularza przy użyciu tej technologii.

Od czego powinniśmy zacząć?


Do rozpoczęcia pracy związanej będzie nam potrzeba dodatkowa paczka - Vuelidate, która zapewni nam walidację naszych dynamicznych pól.
Dodaj paczki do swojego projektu:

npm install @vuelidate/core @vuelidate/validators

# or

yarn add @vuelidate/core @vuelidate/validators


Następnie dodaj w folderze plugins plik z wtyczką vuelidate.ts
import Vuelidate from '@vuelidate/core'

export default defineNuxtPlugin((nuxtApp) => {

nuxtApp.vueApp.use(Vuelidate)

})
 

Setup w Storybloku

Komponenty walidacyjne
Aby uzyskać dynamiczną walidację pól w formularzu, należy utworzyć odpowiednik walidatorów jako komponenty Storybloka. W tym przykładnie użyjemy:

  • required - wymaga, aby pole nie było puste
  • email - wymaga, aby podać poprawny adres e-mail
  • numeric - wymaga, aby podać jedynie cyfry
  • minLength - wymaga, aby podać określoną minimalną długość znaków
  • maxLength - wymaga, aby podać określoną maksymalną długość znaków


     
How to create dynamic forms with Storyblok and Vue.js/Nuxt?_image1_Block library

Ważne jest, aby nazwy komponentów były takie same jak nazwy walidatorów, ze względu na to, że będziemy je dynamicznie mapować na walidatory z pakietu Vuelidate.
Komponenty email, numeric oraz required mają jedno edytowalne pole - komunikat o błędzie.
 

How to create dynamic forms with Storyblok and Vue.js/Nuxt?_image2_Edit email

Komponenty minLength i maxLength mają dodatkowe edytowalne pole, które wyznacza określoną długość.

How to create dynamic forms with Storyblok and Vue.js/Nuxt?_image3_Edit maxLenght

Komponent pola formularza

Tworzymy dynamiczne pole formularza poprzez dodanie komponentu inputField

 

How to create dynamic forms with Storyblok and Vue.js/Nuxt?_image3_Edit inputField

Komponent składa się z pola:

  • name - pole tekstowe, dzięki któremu nadamy polu formularza unikalny identyfikator <input name="" />
  • type - pole pojedyńczego wyboru, z nadanymi opcjami: text, tel, email. Będzie określać typ pola formularza <input type="" />
  • label - pole tekstowe, używane jako nazwa etykiety pola fomularza
  • placeholder - pole tesktowe, które wyświetli się w polu formularza gdy będzie puste <input placeholder="" />
  • validators - bloki z listą walidacji wcześniej przez nas utworzonych


     

Komponent formularza


Teraz tworzymy dynamiczny komponent formularza dynamicForm.
 

How to create dynamic forms with Storyblok and Vue.js/Nuxt?_image4_Edit dynamicform

Składa się on z:

  • inputs - zawiera listę pól formularza (inputField)
  • formEndpoint - adres URL, pod który formularz zostanie wysłany
  • submitButtonText - nazwa jaka wyświetli się w przycisku zatwierdzającym wysłanie formularza
     

Komponenty Vue

Kiedy mamy już przygotowane komponenty i pola po stronie Storybloka, możemy przejść do tworzenia komponentów we Vue. Potrzebujemy dwóch komponentów: DynamicForm.vue, który zawierać będzie dynamiczny formularz, oraz InputField.vue, gdzie będzie się mieścić pojedyncze pole formularza.


DynamicForm.vue

 

Logika
Na początku należy zaimportować walidatory z pakietu Vuelidate oraz funkcję useVualidate do aktywowania walidacji.
import { useVuelidate } from '@vuelidate/core'

import * as validators from '@vuelidate/validators'
W komponencie należy również zadeklarować props pochodzące ze Storybloka.
const DynamicFormProps = defineProps({

 blok: {

   type: Object,

   default: () => ({})

 }

})
Początkowe dane formularza są generowane za pomocą funkcji form. Tworzy ona obiekt, używając do tego unikalnej nazwy pola formularza jako klucz oraz pustego łańcucha znaków jako wartości.
const form = reactive(DynamicFormProps.blok.inputs.reduce(

 (prevFields, inputField) => ({

   ...prevFields,

   [inputField.name]: ''

 }),

 {}

))
Funkcja generateFieldRules() odpowiada za generowanie walidatorów dla danego pola formularza. Tworzymy tu obiekt składający się z nazwy walidatora jako klucz, a wartością jego jest dostarczony przez pakiet Vuelidate domyślny komunikat o błędach lub funkcja, jeżeli element posiada parametr (np. dla walidacji, która definiuje minimalną długość tekstu, należy wywołać funkcje minLenght() i przekazać w niej parametr określający liczbę znaków)
const generateFieldRules = (fieldValidators) => {

 return fieldValidators.reduce(

   (prevValidators, validator) => ({

     ...prevValidators,

     [validator.component]: validator.param ? validators[validator.component](validator.param) : validators[validator.component]

   }),

   {}

 )

}
W zmiennej fieldRules trzymamy nazwy pól formularza z wygenerowanymi walidatorami.
const fieldRules = computed(() => {

 return DynamicFormProps.blok.inputs.reduce(

   (prevFields, inputField) => ({

     ...prevFields,

     [inputField.name]: generateFieldRules(inputField.validators)

   }),

   {}

 )

})
Aby walidacja zaczęła działać, należy aktywować pakiet Vuelidate poprzez wykonanie metody useVualidate, która przyjmuje jako parametry stworzone przez nas wcześniej zmienne. Dzięki temu za pośrednictwem v$ uzyskuje się dostęp do danych oraz opcji.
const v$ = useVuelidate(fieldRules, form)
Ostatnią funkcją jest obsłużenie wysyłki formularza - formSubmit(). Sprawdzając wartość zmiennej $invalid dostajemy informację czy jakiekolwiek pole w formularzu nie przeszło walidacji. W takim wypadku wywołujemy metodę $touch(), która powoduje wyświetlenie się ostrzeżeń o błędach w poszczególnych polach formularza.
const formSubmit = (e) => {

 if (v$.value.$invalid) {

   v$.value.$touch()

   e.preventDefault()

 }

}
Aby komponent InputFields.vue mógł korzystać z walidacji formularza należy mu dostarczyć zmienną v$
provide('v$', v$)
Łącząc wszystkie opisane elementy, dostajemy następującą logikę:
<script setup>

import { useVuelidate } from '@vuelidate/core'

import * as validators from '@vuelidate/validators'

const DynamicFormProps = defineProps({

blok: {

  type: Object,

  default: () => ({})

}

})

 

const form = reactive(DynamicFormProps.blok.inputs.reduce(

(prevFields, inputField) => ({

  ...prevFields,

  [inputField.name]: ''

}),

{}

))

const generateFieldRules = (fieldValidators) => {

return fieldValidators.reduce(

  (prevValidators, validator) => ({

    ...prevValidators,

    [validator.component]: validator.param ? validators[validator.component](validator.param) : validators[validator.component]

  }),

  {}

)

}

 

const fieldRules = computed(() => {

return DynamicFormProps.blok.inputs.reduce(

  (prevFields, inputField) => ({

    ...prevFields,

    [inputField.name]: generateFieldRules(inputField.validators)

  }),

  {}

)

})

 

const formSubmit = (e) => {

if (v$.value.$invalid) {

  v$.value.$touch()

  e.preventDefault()

}

}

 

const v$ = useVuelidate(fieldRules, form)

provide('v$', v$)

</script>

 

Szablon komponentu formularza


W szablonie tym tworzymy formularz, który posiada:

  • action - atrybut określający gdzie wysłać dane formularza po jego przesłaniu
  • formSubmit - wywołanie metody przy próbie wysyłki formularza
  • InputField - komponent zawierający pojedyncze pole formularza
  • button - przycisk wywołujący wysyłkę formularza


<template>

 <form v-if="v$" :id="blok._uid" class="form" method="post" :action="blok.formEndpoint" @submit="formSubmit">

   <InputField v-for="inputField in blok.inputs" :key="inputField.name" :inputField="inputField" />

   <button type="submit" class="btn">

     {{ blok.submitButtonText }}

   </button>

 </form>

</template>
 

InputField.vue


Logika


Na początku należy zaimportować funkcje pozwalającą przyjmowanie danych.
import { inject } from 'vue'
Następnie zadeklarować props pochodzących z komponentu DynamicForm.vue
defineProps({ inputField: Object })
A na koniec stworzyć zmienną, dzięki której będziemy mieć dostęp do walidacji formularza
const v$ = inject('v$')

Szablon komponentu pola formularza

Pojedyncze pole formularza składa się z:
 

  • sprawdzenia, czy pole zostało poprawnie uzupełnione poprzez zmienną v$[inputField.name].$error. W przypadku nieprawidłowej zawartości zostaje dynamicznie dodana dodatkowa klasa.
  • powiązania danych pola za pomocą dyrektywy v-model między elementem a modelem danych Vualidate ($model)
  • obsłużonych błędów walidacji. Dzieje się to za pomocą iteracji po błędach. Jeśli pole posiada dany problem, jest on wyświetlany.


<template>

<div

  :class="{

    'form__group': true,

    'form__group--error': v$[inputField.name].$error,

  }"

>

  <label class="form__label" :for="inputField._uid">{{ inputField.label }}</label>

  <input

    :id="inputField._uid"

    v-model.trim="v$[inputField.name].$model"

    :type="inputField.type"

    :name="inputField.name"

    :placeholder="inputField.placeholder"

    class="form__input"

  >

  <div v-if="v$[inputField.name].$error">

    <div v-for="{ component, errorMessage } in inputField.validators" :key="component" class="form__group__warninig">

      <div v-if="v$[inputField.name][component].$invalid">

        {{ errorMessage }}

      </div>

    </div>

  </div>

</div>

</template>
 

Podsumowanie

Każdy developer prędzej czy później stoi przed wyzwaniem, jakim jest stworzenie dynamicznych formularzy. Dzięki nim klient sam może dodawać oraz edytować pola w formularzach bez ingerencji programisty. 
Przedstawiony przykład można rozwinąć poprzez stworzenie dodatkowych typów pól jak radio, checkbox czy textarea.
 

Tandemite team: Monika_avatar
Monika Harewska
Frontend developer @ Tandemite

Znajdź coś dla siebie

Więcej artykułów po tagach

Tandemite team at industry event

Porozmawiajmy!

Opowiedz, czego potrzebujesz, a my zajmiemy się resztą.

Napisz do nas

Przeczytaj najlepsze branżowe wskazówki od ekspertów PIM. Za darmo!

Napisz do nas

Czekamy na Twoją wiadomość

Tandemite icon: clock

Szybki kontakt

Skontaktujemy się z Tobą w ciągu 24 godzin, żeby jak najszybciej poznaćTwoje potrzeby.

Tandemite icon: paper airplane

Precyzyjna reakcja

Przygotujemy estymację Twojego projektu, uwzględniającą koszty i czas wykonania.

* Pola oznaczone gwiazdką są wymagane
lub upuść brief swojej firmy tutaj. PDF lub DOCX
Więcej informacji o Twoich prawach, w Polityce prywatności i cookie
Ta witryna jest chroniona przez reCAPTCHA i Google Obowiązują Polityka prywatnosci

Używamy plików cookie, aby zapewnić najlepsze wrażenia na naszej stronie internetowej. Jeśli będziesz nadal korzystać z tej strony, zakładamy, że jesteś z niej zadowolony.