Architecture

Introduction

Au cœur du framework FormKit se trouve @formkit/core. Ce package sans dépendance est responsable de presque toutes les fonctions critiques de bas niveau de FormKit, telles que :

  • La configuration
  • L'entrée/sortie de valeurs
  • La propagation des événements
  • La gestion des plugins
  • Le suivi de l'état de l'arbre
  • La gestion des messages
  • Les crochets de cycle de vie

Architecture

La fonctionnalité du noyau de FormKit n'est pas exposée à votre application via une instance centralisée, mais plutôt un ensemble distribué de "nœuds" (FormKitNode), où chaque nœud représente une entrée unique.

Cela reflète le HTML — en fait, la structure du DOM est en réalité un arbre général et les nœuds du noyau de FormKit reflètent cette structure. Par exemple, un formulaire de connexion simple pourrait être représenté par le graphique d'arbre suivant :

Survolez chaque nœud pour voir ses options initiales.

Dans ce diagramme, un nœud form est parent de trois nœuds enfants — email, password et submit. Chaque composant d'entrée dans le graphique "possède" un nœud du noyau de FormKit, et chaque nœud contient ses propres options, configuration, props, événements, plugins, crochets de cycle de vie, etc. Cette architecture garantit que les fonctionnalités principales de FormKit sont découplées du framework de rendu (Vue) — une clé pour réduire les effets secondaires et maintenir des performances extrêmement rapides.

De plus, cette architecture décentralisée permet une flexibilité énorme. Par exemple — un formulaire peut utiliser des plugins différents des autres formulaires dans la même application, un groupe d'entrée peut modifier la configuration de ses sous-entrées, et les règles de validation peuvent même être écrites pour utiliser les props d'une autre entrée.

Nœud

Chaque composant <FormKit> possède un seul nœud central, et chaque nœud doit être de l'un des trois types :

Input vs types de nœuds

Les nœuds centraux sont toujours de l'un des trois types (input, list ou group). Ce ne sont pas les mêmes que les types d'entrée — dont il peut y avoir une variation illimitée. Strictement parlant, toutes les entrées ont 2 types : leur type de nœud (comme input), et leur type d'entrée (comme checkbox).

Input

La plupart des entrées natives de FormKit ont un type de nœud input — elles opèrent sur une valeur unique. La valeur elle-même peut être de n'importe quel type, comme des objets, des tableaux, des chaînes de caractères et des nombres — toute valeur est acceptable. Cependant, les nœuds de type input sont toujours des feuilles — ce qui signifie qu'ils ne peuvent pas avoir d'enfants.

import { createNode } from '@formkit/core'

const input = createNode({
  type: 'input', // par défaut à 'input' si non spécifié
  value: 'hello node world',
})

console.log(input.value)
// 'hello node world'

Liste

Une liste est un nœud qui produit une valeur de tableau. Les enfants d'un nœud de liste produisent une valeur dans le tableau de la liste. Les noms des enfants immédiats sont ignorés — à la place, chacun se voit attribuer un indice dans le tableau de la liste.

import { createNode } from '@formkit/core'

const list = createNode({
  type: 'list',
  children: [
    createNode({ value: 'paprika@example.com' }),
    createNode({ value: 'bill@example.com' }),
    createNode({ value: 'jenny@example.com' }),
  ],
})

console.log(list.value)
// ['paprika@example.com', 'bill@example.com', 'jenny@example.com']

Groupe

Un groupe est un nœud qui produit une valeur d'objet. Les enfants d'un nœud de groupe utilisent leur name pour produire une propriété du même nom dans l'objet de valeur du groupe — <FormKit type="form"> est une instance de groupe.

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [
    createNode({ name: 'meat', value: 'turkey' }),
    createNode({ name: 'greens', value: 'salad' }),
    createNode({ name: 'sweets', value: 'pie' }),
  ],
})

console.log(group.value)
// { meat: 'turkey', greens: 'salad', sweets: 'pie' }

Options

En plus de spécifier le type de nœud lors de l'appel à createNode(), vous pouvez passer n'importe laquelle des options suivantes :

OptionsPar défautDescription
children[]Instances de FormKitNode enfants.
config{}Options de configuration. Celles-ci deviennent les valeurs par défaut de l'objet props.
name{type}_{n}Le nom du nœud/entrée.
parentnullL'instance de FormKitNode parent.
plugins[]Un tableau de fonctions de plugin.
props{}Un objet de paires clé/valeur qui représentent les détails de l'instance de nœud actuelle.
typeinputLe type de FormKitNode à créer (list, group, ou input).
valueundefinedLa valeur initiale de l'entrée.

Config & Props

FormKit utilise un système de configuration basé sur l'héritage. Toutes les valeurs déclarées dans l'option config sont automatiquement transmises aux enfants (et à tous les descendants) de ce nœud, mais pas aux frères et sœurs ou aux parents. Chaque nœud peut remplacer ses valeurs héritées en fournissant sa propre configuration, et ces valeurs seront à leur tour héritées par tous les enfants et descendants plus profonds. Par exemple :

const parent = createNode({
  type: 'group',
  config: {
    color: 'yellow',
  },
  children: [
    createNode({
      type: 'list',
      config: { color: 'pink' },
      children: [createNode(), createNode()],
    }),
    createNode(),
  ],
})

Le code ci-dessus aboutira à ce que chaque nœud ait la configuration suivante :

Remarquez comment le sous-arbre de la liste est rose.
Utilisez props pour lire la config

Il est recommandé de lire les valeurs de configuration à partir de node.props plutôt que de node.config. La section suivante détaille cette fonctionnalité.

Props

Les objets node.props et node.config sont étroitement liés. node.config doit être considéré comme les valeurs initiales pour node.props. props est un objet de forme arbitraire qui contient des détails sur l'instance actuelle du nœud.

La meilleure pratique est de toujours lire les données de configuration et de propriétés à partir de node.props même si la valeur d'origine est définie à l'aide de node.config. Les props explicitement définis ont la priorité sur les options de configuration.

const child = createNode({
  props: {
    flavor: 'cherry',
  },
})
const parent = createNode({
  type: 'group',
  config: {
    size: 'large',
    flavor: 'grape',
  },
  children: [child],
})
console.log(child.props.size)
// affiche : 'large'
console.log(child.props.flavor)
// affiche : 'cherry'
Props des composants FormKit

Lorsque vous utilisez le composant <FormKit>, toutes les props définies pour le type d'entrée type sont automatiquement définies comme propriétés de node.props. Par exemple : <FormKit label="Email" /> résulterait en node.props.label étant Email.

Définir des valeurs

Vous pouvez définir la valeur initiale d'un nœud en fournissant l'option value sur createNode() — mais FormKit est tout au sujet de l'interactivité, alors comment mettons-nous à jour la valeur d'un nœud déjà défini ? En utilisant node.input(value).

import { createNode } from '@formkit/core'

const username = createNode()
username.input('jordan-goat98')
console.log(username.value)
// undefined  👀 attendez — quoi !?

Dans l'exemple ci-dessus, username.value est toujours indéfini immédiatement après avoir été défini parce que node.input() est asynchrone. Si vous avez besoin de lire la valeur résultante après avoir appelé node.input(), vous pouvez attendre la promesse retournée.

import { createNode } from '@formkit/core'

const username = createNode()
username.input('jordan-goat98').then(() => {
  console.log(username.value)
  // 'jordan-goat98'
})

Comme node.input() est asynchrone, le reste de notre formulaire n'a pas besoin de recalculer ses dépendances à chaque frappe. Cela offre également l'opportunité d'effectuer des modifications sur la valeur non stabilisée avant qu'elle ne soit "engagée" dans le reste du formulaire. Cependant — pour une utilisation interne du nœud uniquement — une propriété _value contenant la valeur non stabilisée de l'entrée est également disponible.

Ne pas assigner de valeurs

Vous ne pouvez pas directement assigner la valeur d'une entrée node.value = 'foo'. Au lieu de cela, vous devriez toujours utiliser node.input(value)

Règlement de la valeur

Maintenant que nous comprenons que node.input() est asynchrone, explorons comment FormKit résout le problème de l'arbre "stabilisé". Imaginez qu'un utilisateur tape rapidement son adresse e-mail et appuie sur "entrée" très rapidement — soumettant ainsi le formulaire. Puisque node.input() est asynchrone, des données incomplètes seraient probablement soumises. Nous avons besoin d'un mécanisme pour savoir quand le formulaire entier est "stabilisé".

Pour résoudre cela, les nœuds de FormKit suivent automatiquement les "perturbations" de l'arbre, du sous-arbre et du nœud. Cela signifie que le formulaire (généralement le nœud racine) connaît toujours l'état de stabilisation de tous les champs qu'il contient.

Le graphique suivant illustre ce "comptage des perturbations". Cliquez sur n'importe quel nœud de saisie (bleu) pour simuler l'appel de node.input() et remarquez comment le formulaire entier est toujours conscient du nombre de nœuds "perturbés" à tout moment. Lorsque le nœud racine a un compte de perturbations de 0, le formulaire est stabilisé et sûr à soumettre.

Cliquez sur les champs de saisie (bleu) pour simuler l'appel d'une saisie utilisateur.
Pour vous assurer qu'un arbre donné (formulaire), sous-arbre (groupe) ou nœud (champ de saisie) est "stabilisé", vous pouvez attendre la propriété `node.settled` :
import { createNode } from '@formkit/node'

const form = createNode({
  type: 'group',
  children: [
    createNode(),
    createNode(),
    createNode()
  ],
})
// ...
// interaction utilisateur :
async function someEvent () {
  await form.settled
  // nous savons maintenant que le formulaire est complètement "stabilisé"
  // et que form.value est précis.
}
Le type de formulaire

L'entrée <FormKit type="form"> intègre déjà ce comportement d'attente. Elle n'appellera pas votre gestionnaire @submit tant que votre formulaire n'est pas complètement stabilisé. Cependant, lors de la création de champs de saisie avancés, il peut être utile de comprendre ces principes sous-jacents.

Obtenir le nœud d'un composant

Parfois, il peut être utile d'obtenir l'instance sous-jacente d'un nœud à partir du composant Vue <FormKit>. Il existe trois méthodes principales pour récupérer le nœud d'un champ de saisie.

  • En utilisant getNode() (ou le $formkit.get() du plugin Vue pour l'API Options)
  • En utilisant useFormKitNodeById
  • En utilisant l'événement @node.
  • En utilisant une ref de template.

Utilisation de getNode()

Lorsque vous utilisez FormKit, vous pouvez accéder à un nœud en lui attribuant un id puis en y accédant par cette propriété via la fonction getNode().

warning

Vous devez attribuer un id au champ de saisie pour utiliser cette méthode.

Charger l'exemple en direct
API Options

Lorsque vous utilisez l'API Options de Vue, vous pouvez accéder au même comportement getNode() en utilisant this.$formkit.get().

Utilisation de useFormKitNodeById()

La fonction de composition useFormKitNodeById vous permet d'accéder à un nœud par son id depuis un composant Vue en retournant une ref Vue qui sera peuplée avec l'instance FormKitNode dès qu'elle aura été créée.

Pour d'autres fonctions de composition similaires, consultez la documentation sur les composables.

warning

Vous devez attribuer un id à l'entrée pour utiliser cette méthode.

Charger l'exemple en direct

Utilisation de l'événement nœud

Une autre façon d'obtenir le nœud sous-jacent est d'écouter l'événement @node qui est émis une seule fois lorsque le composant initialise le nœud pour la première fois.

Charger l'exemple en direct

Utilisation d'une référence de template

Attribuer un composant <FormKit> à une ref permet également un accès facile au nœud.

Charger l'exemple en direct

Traversal

Pour parcourir les nœuds au sein d'un groupe ou d'une liste, utilisez node.at(address) — où address est le nom du nœud auquel on accède (ou le chemin relatif vers le nom). Par exemple :

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [createNode({ name: 'email' }), createNode({ name: 'password' })],
})

// Retourne le nœud email
group.at('email')

Si le nœud de départ a des frères et sœurs, il tentera de localiser une correspondance chez les frères et sœurs (en interne, c'est ce que FormKit utilise pour des règles de validation comme confirm:address).

import { createNode } from '@formkit/core'

const email = createNode({ name: 'email' })
const password = createNode({ name: 'password' })
const group = createNode({
  type: 'group',
  children: [email, password],
})

// Accède au frère pour retourner le nœud password
email.at('password')

Traversal profond

Vous pouvez aller plus loin qu'un niveau en utilisant un chemin relatif avec une syntaxe pointée. Voici un exemple plus complexe :

import { createNode } from '@formkit/core'

const group = createNode({
  type: 'group',
  children: [
    createNode({ name: 'team' }),
    createNode({
      type: 'list',
      name: 'users',
      children: [
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email' }),
            createNode({ name: 'password', value: 'foo' }),
          ],
        }),
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email' }),
            createNode({ name: 'password', value: 'fbar' }),
          ],
        }),
      ],
    }),
  ],
})

// affiche : 'foo'
console.log(group.at('users.0.password').value)

Remarquez comment le parcours de la list utilise des clés numériques, c'est parce que le type list utilise automatiquement les index de tableau.

Chemin de traversal de group.at('users.0.password') montré en rouge.
Chemins de tableau

Les adresses de nœuds peuvent également être exprimées sous forme de tableaux. Par exemple, node.at('foo.bar') pourrait être exprimé comme node.at(['foo', 'bar']).

Jetons de parcours

Également disponibles pour utilisation dans node.at() sont quelques "jetons" spéciaux :

JetonDescription
$parentL'ancêtre immédiat du nœud courant.
$rootLe nœud racine de l'arbre (le premier nœud sans parent).
$selfLe nœud courant dans le parcours.
find()Une fonction qui effectue une recherche en largeur d'abord pour une valeur et propriété correspondantes. Par exemple : node.at('$root.find(555, value)')

Ces jetons sont utilisés dans les adresses en syntaxe pointée tout comme vous utiliseriez le nom d'un nœud :

import { createNode } from '@formkit/core'

const secondEmail = createNode({ name: 'email' })

createNode({
  type: 'group',
  children: [
    createNode({ name: 'team', value: 'charlie@factory.com' }),
    createNode({
      type: 'list',
      name: 'users',
      children: [
        createNode({
          type: 'group',
          children: [
            createNode({ name: 'email', value: 'james@peach.com' }),
            createNode({ name: 'password', value: 'foo' }),
          ],
        }),
        createNode({
          type: 'group',
          children: [
            secondEmail, // Nous allons commencer ici.
            createNode({ name: 'password', value: 'fbar' }),
          ],
        }),
      ],
    }),
  ],
})

// Naviguer du second email au premier
console.log(secondEmail.at('$parent.$parent.0.email').value)
// affiche : charlie@factory.com
Chemin de parcours de secondEmail.at('$parent.$parent.0.email') montré en rouge.

Événements

Les nœuds ont leurs propres événements qui sont émis pendant le cycle de vie du nœud (sans rapport avec les événements de Vue).

Ajouter un écouteur

Pour observer un événement donné, utilisez node.on().

// Écouter toute propriété étant définie ou changée.
node.on('prop', ({ payload }) => {
  console.log(`la propriété ${payload.prop} a été définie à ${payload.value}`)
})

node.props.foo = 'bar'
// affiche : la propriété foo a été définie à bar

Les fonctions de rappel des gestionnaires d'événements reçoivent toutes un seul argument de type FormKitEvent, la structure de l'objet est :

{
  // Le contenu de l'événement — une chaîne, un objet, etc.
  payload: { cause: 'glace', duration: 200 },
  // Le nom de l'événement, cela correspond au premier argument de node.on().
  name: 'brain-freeze',
  // Si cet événement doit remonter au parent suivant ou non.
  bubble: true,
  // Le FormKitNode original qui a émis l'événement.
  origin: node,
}

Les événements des nœuds (par défaut) remontent dans l'arbre des nœuds, mais node.on() ne répondra qu'aux événements émis par le même nœud. Cependant, si vous souhaitez également attraper les événements remontant des descendants, vous pouvez ajouter la chaîne .deep à la fin du nom de votre événement :

import { createNode } from '@formkit/core'

const group = createNode({ type: 'group' })

group.on('created.deep', ({ payload: child }) => {
  console.log('nœud enfant créé :', child.name)
})

const child = createNode({ parent: group, name: 'party-town-usa' })
// affiche : 'nœud enfant créé : party-town-usa'

Supprimer l'écouteur

Chaque appel pour enregistrer un observateur avec node.on() retourne un « reçu » — une clé générée aléatoirement — qui peut être utilisée plus tard pour arrêter d'observer cet événement (similaire à setTimeout() et clearTimeout()) en utilisant node.off(reçu).

const reçu = node.on('input', ({ payload }) => {
  console.log('reçu en entrée : ', payload)
})
node.input('foobar')
// affiche : 'reçu en entrée : foobar'
node.off(reçu)
node.input('fizz buzz')
// pas d'affichage

Événements principaux

Voici une liste complète de tous les événements émis par @formkit/core. Le code tiers peut émettre des événements supplémentaires non inclus ici.

NomCharge utileBullesDescription
commitquelconqueouiÉmis quand la valeur d'un nœud est validée mais avant qu'elle ne soit transmise au reste du formulaire.
config:{propriété}quelconque (la valeur)ouiÉmis à chaque fois qu'une option de configuration spécifique est définie ou modifiée.
count:{propriété}quelconque (la valeur)nonÉmis à chaque fois qu'une valeur de compteur d'un grand livre change.
childFormKitNodeouiÉmis lorsqu'un nouveau nœud enfant est ajouté, créé ou assigné à un parent.
createdFormKitNodeouiÉmis immédiatement avant que le nœud ne soit retourné lors de l'appel à createNode() (les plugins et fonctionnalités ont déjà été exécutés).
definedFormKitTypeDefinitionouiÉmis lorsque le "type" d'un nœud est défini, cela se produit généralement pendant createNode().
destroyingFormKitNodeouiÉmis lorsque node.destroy() est appelé, après qu'il a été détaché de tout parent.
dom-input-eventEventouiÉmis lorsque le gestionnaire DOMInput est appelé, utile pour obtenir l'événement d'entrée HTML original dans le cœur.
inputquelconque (la valeur)ouiÉmis lorsque node.input() est appelé — après que le crochet input a été exécuté.
message-addedFormKitMessageouiÉmis lorsqu'un nouveau message a été ajouté à node.store.
message-removedFormKitMessageouiÉmis lorsqu'un message de node.store a été supprimé.
message-updatedFormKitMessageouiÉmis lorsqu'un message de node.store a été modifié.
mountedaucunouiÉmis lorsque le composant <FormKit> qui possède ce nœud est monté sur le DOM.
prop:{nomProp}quelconque (la valeur)ouiÉmis à chaque fois qu'une prop spécifique est définie ou modifiée.
prop{ prop: string, value: any }ouiÉmis à chaque fois qu'une prop est définie ou modifiée.
resetFormKitNodeouiÉmis à chaque fois qu'un formulaire ou un groupe est réinitialisé.
settledbooléennonÉmis à chaque fois qu'un comptage de perturbation d'un nœud se stabilise ou se déstabilise.
settled:{nomCompteur}booléennonÉmis à chaque fois qu'un compteur spécifique d'un grand livre se stabilise (retourne à zéro).
unsettled:{nomCompteur}booléennonÉmis à chaque fois qu'un compteur spécifique d'un grand livre devient instable (dépasse zéro).
textchaîne ou FormKitTextFragmentnonÉmis après que le crochet text a été exécuté — généralement lors du traitement de texte d'interface qui a pu être traduit.
Événements de prop lors de changements de configuration

Lorsqu'une option de configuration change, tous les nœuds héritiers (y compris le nœud d'origine) émettront également des événements prop et prop:{nomProp}, tant qu'ils ne remplacent pas cette propriété dans leurs propres objets props ou config.

Émission d'événements

Les événements Node sont émis avec node.emit(). Vous pouvez utiliser cette fonctionnalité pour émettre vos propres événements synthétiques depuis vos propres plugins.

node.emit('myEvent', payloadGoesHere)

Un troisième argument facultatif bubble est également disponible. Lorsqu'il est défini sur false, il empêche votre événement de remonter à travers l'arborescence du formulaire.

Hooks

Les hooks sont des dispatchers de middleware qui sont déclenchés pendant les opérations du cycle de vie prédéfinies. Ces hooks permettent au code externe d'étendre la fonctionnalité interne de @formkit/core. Le tableau suivant détaille tous les hooks disponibles :

HookValeurDescription
classes
{
property: string,
classes: Record<string, boolean>
}
Dispatché après que toutes les opérations de classe ont été exécutées, avant la conversion finale en chaîne de caractères.
commitanyDispatché lors de la définition de la valeur d'un nœud après l'input et le debounce de node.input() est appelé.
commitRawanyDispatché lors de la définition de la valeur d'un nœud après l'input et le debounce de node.input() est appelé.
errorstringDispatché lors du traitement d'une erreur lancée — les erreurs sont généralement des entrées, et la sortie finale devrait être une chaîne de caractères.
initFormKitNodeDispatché après que le nœud est initialement créé mais avant qu'il soit retourné dans createNode().
inputanyDispatché de manière synchrone à chaque événement d'entrée (à chaque frappe) avant commit.
messageFormKitMessageDispatché lorsqu'un message est en train d'être défini sur node.store
prop
{
prop: string,
value: any
}
Dispatché lorsqu'une prop est en train d'être assignée.
setErrors{ localErrors: ErrorMessages, childErrors?: ErrorMessages }Dispatché lorsque des erreurs explicites sont en train d'être définies sur un nœud (pas des erreurs de validation).
submitRecord<string, any>Dispatché lorsque le formulaire FormKit est soumis et passe la validation. Ce hook vous permet de modifier les valeurs du formulaire (clonées) avant qu'elles ne soient passées au gestionnaire de soumission
textFormKitTextFragmentDispatché lorsqu'une chaîne de caractères générée par FormKit doit être affichée — permettant à i18n ou à d'autres plugins d'intercepter.

Middleware de crochet

Pour utiliser ces crochets, vous devez enregistrer un middleware de crochet. Un middleware est simplement une fonction qui accepte 2 arguments — la valeur du crochet et next — une fonction qui appelle le middleware suivant dans la pile et retourne la valeur.

Pour enregistrer un middleware, passez-le au node.hook que vous souhaitez utiliser :

import { createNode } from '@formkit/core'

const node = createNode()

// Cela transformerait tous les labels en "Different label!"
node.hook.prop((payload, next) => {
  if ((payload.prop = 'label')) {
    payload.value = 'Different label!'
  }
  return next(payload)
})
Utilisation avec des plugins

Les crochets peuvent être enregistrés n'importe où dans votre application, mais l'endroit le plus courant où les crochets sont utilisés est dans un plugin.

Plugins

Les plugins sont le mécanisme principal pour étendre la fonctionnalité de FormKit. Le concept est simple — un plugin est juste une fonction qui accepte un nœud. Ces fonctions sont ensuite automatiquement appelées lorsqu'un nœud est créé, ou lorsque le plugin est ajouté au nœud. Les plugins fonctionnent de manière similaire aux options de configuration — ils sont automatiquement hérités par les enfants et les descendants.

import { createNode } from '@formkit/core'

// Un plugin pour changer la valeur d'une propriété.
const myPlugin = (node) => {
  if (node.type === 'group') {
    node.props.color = 'yellow'
  } else {
    node.props.color = 'teal'
  }
}

const node = createNode([
  plugins: [myPlugin],
  children: [createNode()]
])

Dans l'exemple ci-dessus, le plugin est seulement défini sur le parent, mais l'enfant hérite également du plugin. La fonction myPlugin sera appelée deux fois — une fois pour chaque nœud dans le graphe (qui n'en a que deux dans cet exemple) :

Le plugin est hérité par l'enfant, mais exécuté indépendamment.

Bibliothèque

En plus d'étendre et de modifier les nœuds, les plugins jouent un rôle supplémentaire — exposer des bibliothèques d'entrées. Une « bibliothèque » est une fonction assignée à la propriété library d'un plugin qui accepte un nœud et détermine s'il sait comment « définir » ce nœud. Si c'est le cas, elle appelle node.define() avec une définition d'entrée.

Par exemple, si nous voulions créer un plugin qui exposait quelques nouvelles entrées : italy et france, nous pourrions écrire un plugin pour le faire :

Charger l'exemple en direct

Les développeurs expérimentés remarqueront quelques propriétés intéressantes de ce modèle de bibliothèque de plugin :

  1. Plusieurs bibliothèques d'entrées peuvent être installées sur le même projet.
  2. Les plugins (et les bibliothèques) peuvent être exposés localement, par formulaire, groupe ou globalement.
  3. Un plugin peut regrouper de nouvelles entrées avec la logique du plugin, rendant l'installation simple pour les utilisateurs finaux.
  4. La fonction de bibliothèque a un contrôle total sur les conditions qui résultent en un appel à node.define(). Fréquemment, il s'agit simplement de vérifier node.props.type, mais vous pouvez définir différentes entrées en fonction d'autres conditions, comme si une propriété particulière est définie.
Apprenez à créer vos propres entrées personnaliséesDocs d'entrée personnalisée

Magasin de messages

Chaque nœud possède son propre magasin de données. Les objets dans ces magasins sont appelés "messages" et ces messages sont particulièrement précieux pour trois cas d'utilisation principaux :

  • Afficher des informations sur le nœud à un utilisateur avec le support i18n (le plugin de validation l'utilise).
  • "Bloquer" la soumission de formulaire.
  • Magasin de données général pour les auteurs de plugins.

Chaque message (FormKitMessage en TypeScript) dans le magasin est un objet avec la structure suivante :

{
  // Indique si ce message bloque la soumission du formulaire ou non (par défaut : false).
  blocking: true,
  // Doit être une chaîne de caractères unique (par défaut : chaîne aléatoire).
  key: 'yourkey',
  // (optionnel) Objet de métadonnées à propos de ce message (par défaut : {}).
  meta: {
    // (optionnel) Si défini, i18n utilise cela au lieu de la clé pour trouver les messages de la locale.
    messageKey: 'i18nKey',
    // (optionnel) Si défini, ces arguments seront étalés à la fonction locale i18n.
    i18nArgs: [...any],
    // (optionnel) Si défini à false, le message vérifiera la localisation.
    localize: true,
    // (optionnel) La locale du message (par défaut : node.config.locale)
    locale: 'en',
    // Toute autre métadonnée que vous désirez.
    ...any
  },
  // Une catégorie arbitraire à laquelle ce message appartient (à des fins de filtrage).
  // Par exemple : 'validation' ou 'success' (par défaut : 'state')
  type: string,
  // (optionnel) devrait être une chaîne de caractères, un nombre ou un booléen (par défaut : undefined).
  value: 'Oups, notre serveur est en panne !',
  // Ce message doit-il être montré aux utilisateurs finaux ? (par défaut : true)
  visible: true
}
Assistant de création de message

Une fonction d'assistance createMessage({}) peut être importée depuis @formkit/core pour fusionner vos données de message avec les valeurs par défaut ci-dessus afin de créer un nouvel objet message.

Lire et écrire des messages

Pour ajouter ou mettre à jour un message, utilisez node.store.set(FormKitMessage). Les messages sont ensuite disponibles sur node.store.{messageKey}

import { createMessage, createNode } from '@formkit/core'

const node = createNode()
const message = createMessage({
  key: 'clickHole',
  value: 'Veuillez cliquer 100 fois.',
})

node.store.set(message)

console.log(node.store.clickHole.value)
// affiche : 'Veuillez cliquer 100 fois.'
Locales des messages

Les messages seront automatiquement traduits si le plugin @formkit/i18n est installé et qu'une clé correspondante est disponible dans la locale active. Lisez la documentation i18n.

Grand livre

L'une des clés de la performance de FormKit est sa capacité à compter efficacement les messages correspondant à des critères donnés (dans le magasin), puis à tenir un compte courant de ces messages à mesure que des modifications sont apportées (y compris depuis les nœuds enfants). Ces compteurs sont créés en utilisant node.ledger.

Créer un compteur

Disons que nous voulons compter combien de messages sont actuellement affichés. Nous pourrions le faire en comptant les messages dont la propriété visible est définie sur true.

Charger l'exemple en direct

Remarquez que le second argument de node.ledger.count() est une fonction. Cette fonction accepte un message en argument et attend en retour une valeur booléenne, indiquant si ce message doit être compté ou non. Cela vous permet de créer des compteurs arbitraires pour tout type de message.

Lors de l'utilisation d'un compteur sur un nœud group ou list, le compteur se propagera dans l'arbre en additionnant la valeur de tous les messages passant la fonction de critère, puis en suivant ce compte pour les changements dans le magasin.

Compteur de validation

Le plugin de validation déclare déjà un compteur appelé blocking qui compte la propriété de blocage de tous les messages. C'est ainsi que les formulaires FormKit savent si tous leurs enfants sont "valides".