Manuel de référence
    • Introduction
    • Smart Data
    • Sécurité
    • Workflow
    • Les essentiels de l'API PHP
    • Composants graphiques
    • UIs de Smart Element
    • Internationalisation
    • Scripts
    • Module
    • API REST
    • Routes
    • Moteurs de transformation
    • Recherche générale
    • Supervision
    • Techniques avancées
    • Tableaux de bord
    • Workers
    Anakeen Platform 4
    Anakeen
    • Introduction
    • Smart Data
    • Sécurité
    • Workflow
    • Les essentiels de l'API PHP
    • Composants graphiques
    • UIs de Smart Element
    • Internationalisation
    • Scripts
    • Module
    • API REST
    • Routes
    • Moteurs de transformation
    • Recherche générale
    • Supervision
    • Techniques avancées
    • Tableaux de bord
    • Workers
    Anakeen Platform 4
    Anakeen
    • Introduction
    • Préparation de la page
      • La CSS
      • Les traductions
      • Exemple
    • Authentication
      • Initialisation
      • Description
        • Fonctionnement général
        • Mot de passe oublié
      • Propriétés
        • authentLanguage (String, default: "fr_FR, en_US")
        • defaultLanguage (String, default: "fr_FR")
      • Événements
        • beforeLogin
        • afterLogin
        • beforeRequestResetPassword
        • afterRequestResetPassword
        • beforeApplyResetPassword
        • afterApplyResetPassword
    • Identity
      • Description
      • Initialisation
      • Propriétés
        • large
        • email-alterable
        • password-alterable
      • Événements
        • beforeUserLoaded
        • afterUserLoaded
        • beforeMailAddressChange
        • afterMailAddressChange
        • beforePasswordChange
        • afterPasswordChange
    • Logout
      • Description
      • Initialisation
      • Propriétés
        • Title
        • withCloseConfirmation
        • autoDestroy
      • Événements
        • beforeLogout
        • afterLogout
        • logoutCanceled
      • Exemples
        • Composant avec l'icône par défaut
        • Composant avec un contenu personnalisé
        • Composant avec icône personnalisée
    • Smart Criteria
      • Description
      • Initialisation
      • Concepts
        • Types de filtre
        • Structure des filtres
        • Logiques de filtrage
      • Propriétés
        • config: La configuration initiale
        • standalone: Configuration complète côté client
        • submit: Bouton de validation
        • force: Popup de confirmation
        • responsiveColumns: Affichage multi-colonne
        • noCheck: Empêcher l'affichage d'erreurs
      • Slots
      • Méthodes
        • getFilters()
        • getCriteriaForm()
        • loadValues(filterValues: SmartFilter)
        • Méthodes de Smart Form
      • Evénements
        • smartCriteriaReady
        • smartCriteriaChange
        • smartCriteriaError
        • smartCriteriaValidated
        • smartCriteriaSubmitClick
        • smartCriteriaEnterKey
        • Evènements de Smart Form
      • Cas d'usages
        • Operateur non modifiable
        • Aide à la saisie
        • Lien avec une SmartGrid
        • Recherche générale
    • Smart Element
      • Description
      • Initialisation
      • Propriétés
        • initid (Number | String, default: 0)
        • view-id (String, default: "!defaultConsultation
        • revision (Number, default: -1)
        • custom-client-data (Object, default: null)
        • browser-history (Boolean, default: false)
      • Événements
        • documentLoaded
        • Évènements du widget interne
      • Slots
        • loading
      • Méthodes
      • Exemples
        • Ajouter une bordure et la propriété title pour tous les Smart Fields
        • Afficher un message à chaque modification de valeur de Smart Field
    • Smart Element Grid
      • Description
      • Initialisation
        • Configuration des colonnes d’une grille
        • Configuration d’une colonne abstraite de la grille
        • Configuration de la colonne d’actions de la grille
      • Propriétés
        • collection (String)
        • controller (String)
        • defaultExportButton (Boolean)
        • exportOptions (Object)
        • contextTitles (Boolean, default: true)
        • contextTitlesSeparator (String, default: "-")
        • emptyCellText (String, default: "")
        • sortable (Boolean | SmartGridSortConfig, default: DEFAULT_SORT)
        • filterable (Boolean ou Object, default: true)
        • pageable (Boolean | SmartGridPageSize, default: DEFAULT_PAGER)
        • refresh (Boolean, default: false)
        • autoScrollTop (Boolean, default: true]) {#autoScrollTop}
        • reorderable (Boolean, default: false)
        • resizable (Boolean, default: true)
        • persistStateKey (String, default:"")
        • customData (Object)
        • kendoProps
        • smartCriteriaValue (object, default: {})
        • filterOption (FilterOptions , default: FilterOptions.NOCASE = 2)
      • Événements
        • gridReady
        • beforeConfig
        • afterConfig
        • beforeContent
        • afterContent
        • beforeGridCellRender
        • rowClick
        • rowActionClick
        • beforeDocidLink
        • beforeGridExport
        • beforePollingGridExport
        • dataBound
        • selectionChange
        • afterRestoreConfiguration
        • afterSaveConfiguration
        • beforeSaveConfiguration
        • beforeRestoreConfiguration
        • gridError
        • pageChange
      • Slots
        • Description
        • Initialisation
        • cellTemplate
        • ank-grid-pager
        • ank-smart-element-grid-expand-button
        • ank-smart-element-grid-export-button
        • ank-smart-element-grid-columns-button
      • Méthodes
        • export
        • addFilter
        • refreshGrid
        • addSort
        • selectSmartElements
        • expandColumns
        • restoreConfiguration
        • saveConfiguration
        • resetConfiguration
        • displayColumns
        • setOverlay
        • updateOverlay
        • getExportFile
      • Cas d’usages
        • Recherche générale
    • Smart Element List
      • Description
      • Initialisation
      • Propriétés
      • Événements
        • itemSelected
        • filterChange
        • filterInput
        • pageChange
        • beforeContent
        • dataBound
      • Slots
        • header
        • label
        • search
        • item
        • footer
        • pager
      • Méthodes
        • setCollection
        • filterList
        • refreshList
        • selectSmartElement
        • clearListFilter
        • scrollToActiveItem
      • Exemples
        • Affichage des Smart Elements de la Smart Structure "DEVBILLL"
        • Affichage d'une collection "MyCollection" après initialisation du composant
        • Affichage d'une collection "MyCollection" avec gestion d'événements et non sélectionnable
    • Smart Element Tab
      • Installation
      • Tabs component
        • Propriétés
        • Événements
        • Exemple d'utilisation
        • Exemple d'utilisation
        • Méthodes
        • Exemple d'utilisation
      • Smart Element Tab component
        • Description
        • Propriétés
        • Slots
        • Événements
        • Méthodes
      • Tab component
        • Description
        • Propriétés
        • Événements
        • Méthodes
        • Exemple
      • Exemple
    • Smart Form
      • Description {#sf-description}
      • Initialisation {#sf-initialisation}
      • Propriétés {#sf-properties}
        • config.structure (Smart Form Structure) {#sf-config-structure}
        • config.structure (Autocomplete) {#sf-config-autocomplete}
        • config.renderOptions (Smart Form RenderOptions) {#sf-config-renderoptions}
        • config.menu (Smart Form Menu)
        • config.values (Smart Form Values) {#sf-config-values}
      • Événements {#sf-events}
    • Un exemple
      • Ajout de la libraire
      • Mise en place du code

    # Smart Form

    # Description

    Le composant Smart Form est un composant Vuejs permettant de configurer un formulaire web avec les caractéristiques des Smart Elements.

    Le formulaire est décrit avec les caractéristiques suivantes :

    1. La structure : contient les caractéristiques des champs du formulaire
    2. La représentation : contient les options de représentations des champs du formulaire
    3. La barre de menu : contient les caractéristiques des éléments contenus dans le menu
    4. Les valeurs d'initialisation

    # Initialisation

    Le composant AnkSmartForm est défini dans la bibliothèque "@anakeen/user-interfaces/components/lib/AnkSmartForm.esm" et la CSS "@anakeen/user-interfaces/components/scss/AnkSmartElement.scss".

    WARNING

    Ce composant est asynchrone , il faut donc le charger manière asynchrone dans vue (avec une closure). De plus, pour accéder au composant il faut attendre que celui-ci soit monté, un évènement vue @smartElementMounted est mis à disposition pour pouvoir déclencher une méthode à ce moment.

    WARNING

    Ce composant doit être rendu dans un contenant ayant une taille donc pas en height=auto.

    Exemple d'initialisation

    <template>
      <div>
        <ank-smart-form :config="json" />
      </div>
    </template>
    <script>
    
    import AnkSmartForm from "@anakeen/user-interfaces/components/lib/AnkSmartForm.esm";
    import "@anakeen/user-interfaces/components/scss/AnkSmartElement.scss";
    
    export default {
      components: {
        AnkSmartForm: () => AnkSmartForm
      },
      data: () => {
        return {
          json: {
            title: "Formulaire minimaliste",
            type: "Demande de renseignement",
            structure: [
              {
                label: "Identification",
                name: "my_fr_ident",
                type: "frame",
                content: [
                  {
                    label: "Objet de la requête",
                    name: "my_title",
                    type: "text"
                  },
                  {
                    label: "Description de la requête",
                    name: "my_request",
                    type: "longtext"
                  }
                ]
              }
            ]
          }
        };
      }
    };
    </script>
    

    Aperçu du formulaire

    Formulaire minimaliste

    # Propriétés

    Le composant dispose des propriétés suivantes :

    • config. Cette propriété est un objet qui permet de configurer l'ensemble du formulaire hormis les événements. Les événements sont configurables de manière traditionnelle voir le paragraphe ci-dessous.

    • options : Options supplémentaires :

      • withCloseConfirmation : booléen : Si l'option est à false, aucune confirmation n'est demandée à l'utilisateur dans le cas où le formulaire à remplacer est modifié. Par défaut, la valeur est true.

    # config.structure(Smart Form Structure)

    La structure définit les champs du formulaire et leur organisation. Les champs sont typés comme les Smart Fields.

    La structure est soumise aux mêmes contraintes que celles des Smart Fields, à savoir :

    • Un champ de structure de type "tab" ne peut pas être contenu dans un autre champ de structure
    • Un champ de structure de type "frame" ne peut être contenu que dans un champ de structure de type "tab"
    • Un champ de structure de type "array" ne peut être contenu que dans un champ de structure de type "frame"
    • Un champ non structurant doit être dans un champ de structure de type "frame" ou de type "array"

    Un champ contient les propriétés suivantes:

    • name : identifiant du champ unique dans la structure
    • label : libellé du champ (le libellé est égal name s'il n'est pas défini)
    • type : type du champ :account array, color, date, docid, double, enum, file, frame, htmltext, image, int, integer, json, longtext, money, password, tab, time, timestamp, xml,text
    • display : [write, read, none] - type d'affichage'
      • write: Affiche le champ modifiable
      • read: Affiche le champ non modifiable
      • none: n'affiche pas le champ
    • content: Liste des champs contenus dans le champ de structure (seulement pour les types tab, frame, array)

    Configuration JSON

    {
      "title": "Formulaire standard",
      "type": "Demande de renseignement",
      "structure": [
        {
          "label": "Identification",
          "name": "my_fr_ident",
          "type": "frame",
          "content": [
            {
              "label": "Objet",
              "name": "my_title",
              "type": "text"
            },
            {
              "label": "Description de la requête",
              "name": "my_request",
              "type": "longtext"
            }
          ]
        },
        {
          "label": "Informations",
          "name": "my_t_info",
          "type": "tab",
          "content": [
            {
              "label": "Identité",
              "name": "my_fr_info",
              "type": "frame",
              "content": [
                {
                  "label": "Prénom",
                  "name": "my_firstname",
                  "type": "text"
                },
                {
                  "label": "Nom",
                  "name": "my_lastname",
                  "type": "text"
                }
              ]
            }
          ]
        },
        {
          "label": "Localisation",
          "name": "my_t_map",
          "type": "tab",
          "content": [
            {
              "label": "Adresse",
              "name": "my_fr_address",
              "type": "frame",
              "content": [
                {
                  "label": "Rue",
                  "name": "my_street",
                  "type": "text"
                },
                {
                  "label": "Code postal",
                  "name": "my_postalcode",
                  "type": "text"
                },
                {
                  "label": "Ville",
                  "name": "my_town",
                  "type": "text"
                }
              ]
            }
          ]
        }
      ]
    }
    

    Résultat

    Structure du formulaire

    # Spécificité champ docid

    Les champs de type docid ont deux propriétés supplémentaires :

    • typeFormat : Nom logique de la Smart Structure pour filtrer l'aide à la saisie
    • multiple : (bool) : Indique si le champ peut contenir plusieurs valeurs

    Configuration JSON : Docid

    {
      "title": "Test Docid",
      "type": "Demande de renseignement",
      "structure": [
        {
          "label": "Identification",
          "name": "my_fr_ident",
          "type": "frame",
          "content": [
            {
              "label": "Facture",
              "name": "my_request",
              "type": "docid",
              "typeFormat": "DEVBILL"
            },
            {
              "label": "Collègues",
              "name": "my_pfam",
              "type": "docid",
              "typeFormat": "DEVPERSON",
              "multiple": true
            }
          ]
        }
      ]
    }
    

    Résultat : Un champ simple et un champ multiple

    Structure du formulaire

    # Spécificité champ account

    Les champs de type account ont deux propriétés supplémentaires :

    • typeFormat : Nom logique de la Smart Structure pour filtrer l'aide à la saisie par défaut IUSER.
    • multiple : (bool) : Indique si le champ peut contenir plusieurs valeurs
    • options.match : ([user, group, role]) : Indique le type de compte à filtrer par défaut "user"

    Configuration JSON : Account

    
    {
        "title": "Test Account",
        "icon": "/api/v2/images/assets/sizes/24x24c/se-iuser.png",
        "structure": [
            {
                "label": "Identification",
                "name": "my_fr_ident",
                "type": "frame",
                "content": [
                    {
                        "label": "Workers",
                        "name": "my_workers",
                        "type": "account",
                        "multiple": true
                    },
                    {
                        "label": "Labs",
                        "name": "my_labs",
                        "type": "account",
                        "options": {
                            "match": "group"
                        },
                        "multiple": true
                    }
                ]
            }
        ]
    }

    Résultat : Un champ filtrant les utilisateurs et un champ filtrant les groupes

    Structure du formulaire

    # Spécificité champ enum

    Les champs de type enum ont deux propriétés supplémentaires :

    • typeFormat : Nom logique de la Smart Structure pour filtrer l'aide à la saisie
    • multiple : (bool) : Indique si le champ peut contenir plusieurs valeurs

    Configuration JSON : Enum

    
    {
        "title": "Enum",
        "structure": [
            {
                "content": [
                    {
                        "label": "Fruits",
                        "name": "my_fruit",
                        "type": "enum",
                        "enumItems": [
                            {
                                "key": "orange",
                                "label": "Orange"
                            },
                            {
                                "key": "apple",
                                "label": "Pomme"
                            },
                            {
                                "key": "pear",
                                "label": "Poire"
                            }
                        ],
                        "multiple": true
                    },
                    {
                        "label": "Criticité",
                        "name": "my_level",
                        "type": "enum",
                        "enumItems": [
                            {
                                "key": "low",
                                "label": "Faible"
                            },
                            {
                                "key": "medium",
                                "label": "Moyen"
                            },
                            {
                                "key": "hight",
                                "label": "Élevé"
                            }
                        ]
                    }
                ],
                "label": "My first frame",
                "name": "my_firstframe",
                "type": "frame"
            }
        ]
    }

    Résultat : Enum simple et multiple

    Structure du formulaire

    # Spécificité champ array

    Les champs de type array ont une propriété supplémentaire :

    • content : Contient les champs composant les colonnes du tableaux

    Configuration JSON : Tableau

    {
      "title": "Tableau",
      "structure": [
        {
          "label": "Correspondances",
          "name": "my_frame",
          "type": "frame",
          "content": [
            {
              "label": "Trajets",
              "name": "my_localisation",
              "type": "array",
              "content": [
                {
                  "label": "Ville",
                  "name": "my_town",
                  "type": "text"
                },
                {
                  "label": "Quand",
                  "name": "my_date",
                  "type": "date"
                }
              ]
            }
          ]
        }
      ]
    }

    Résultat : Un tableau à 2 colonnes

    Structure du formulaire

    # config.structure (Autocomplete)

    Un sélecteur de proposition peut être ajouté sur les types "text", "docid" et "account". Ce sélecteur permet d'ajouter une autocomplétion comme cela est possible sur les smart fields.

    Propriété du champ structure.<field> Type Description
    autocomplete.url string (obligatoire) Url d'accès à la route délivrant les données pour l'aide à la saisie
    autocomplete.inputs object Liste de correspondances pour les données d'entrées
    autocomplete.outputs object (obligatoire) Liste de correspondances pour les données de sorties

    La propriété autocomplete.url doit indiquer une route valide. Cette route doit retourner des données au format "autocomplete" attendu. Pour cela, le code de la route doit utiliser la classe Anakeen\SmartAutocomplete permettant de renvoyer une réponse standard pour l'aide à la saisie. Cette url peut aussi avoir des parties variables en indiquant le nom des champs entre accolades simples (ex: "/my/api/{my_field}")

    La déclaration de la route se fait de façon standard. Il faut que la méthode HTTP soit POST car les données du formulaire sont transmises via cette méthode à la route afin de pouvoir avoir accès au données du formulaire qui servent de données d'entrée.

    Les méthodes de manipulation de la classeAnakeen\SmartAutocomplete sont :

    Méthode Argument Retour Description
    addMessage ApiMessage this Ajoute un message à afficher sur le sélecteur de liste
    getFilterValue string string Retourne la valeur courante du champ où se trouve l'aide à la saisie
    getInputValue string string ou array Retourne la valeur du champ décrit par autocomplete.inputs. Pour les tableaux, si le champ est dans le même tableau que l'aide à la saisie alors ce sera la valeur de la cellule. Sinon si le champ est multiple le résultat est un tableau de valeur
    getResponse Aucun Slim\Http\response Réponse formatée à retourner au serveur
    setEntryLabel Closure ou string this Spécification des éléments affichés sur la liste (soit une fonction, soit une chaîne Mustache . Les variables sont les index des données fournies dans setEntryData()
    setEntryData array this Enregistre les données de retour de l'aide à la saisie. Les données sont sous la forme d'un tableau indexé.
    setError string this Ajout d'un message d'erreur qui sera affiché sur la liste

    # Exemple basique : aide à la saisie à une seule sortie

    Cette exemple montre comme réaliser une aide à la saisie permettant à un champ de choisir parmi une liste de pays provenant du serveur.

    L'aide à la saisie nécessite 3 déclarations :

    1. La déclaration de la configuration de l'aide à la saisie dans le Smart Form structure.<field>.autocomplete (référence l'url de la route et les retours)
    2. La déclaration de la route : /my/countries/ (référence la classe PHP)
    3. Le code de la classe PHP (My\AutoCountries) de la route (qui retourne les données indexées)

    Déclaration de la route `/my/countries/` . Fichier `src/config/SmartDataEngine/myAutocompletes.xml`

    <?xml version="1.0"?>
    <sde:config xmlns:sde="https://platform.anakeen.com/4/schemas/sde/1.0">
        <sde:routes namespace="My">
            <sde:route name="Autocomplete:Countries">
                <sde:priority>0</sde:priority>
                <sde:callable>My\AutoCountries</sde:callable>
                <sde:method>POST</sde:method>
                <sde:pattern>/my/countries/</sde:pattern>
                <sde:description>Get countries</sde:description>
            </sde:route>
    
        </sde:routes>
    </sde:config>
    

    Classe PHP `My\AutoCountries` pour retourner les résultats (Fichier `vendor/My/AutoCountries.php`)

    <?php
    namespace My;
    
    use Anakeen\SmartAutocomplete;
    use Psr\Http\Message\ResponseInterface as Response;
    use Psr\Http\Message\ServerRequestInterface as Request;
    
    /**
     * Class AutoCountries
     *
     * Données retournées :
     *  - "Country"
     */
    class AutoCountries
    {
        public function __invoke(Request $request, Response $response, $args)
        {
    
            $autocomplete = new SmartAutocomplete($request, $response);
    
            // Get filter form input value
            $inputValue = $autocomplete->getFilterValue();
    
            // Here my data to returns
            $countries = ["France", "Italie", "Espagne"];
    
            $autoCompleteData = [];
            foreach ($countries as $country) {
                if (!$inputValue || preg_match(sprintf("/%s/i", preg_quote($inputValue, "/")), $country) > 0) {
                    // Return only if match input
                    $autoCompleteData[] = [
                        "Country" => $country
                    ];
                }
            }
            $autocomplete->setEntryData($autoCompleteData);
            $autocomplete->setEntryLabel("<p>{{Country}}</p>");
    
            return $autocomplete->getResponse();
        }
    
    }
    
    

    L'exemple ci-dessous indique une aide à la saisie sur le champ "my_country". Elle référence la route /my/countries/. Cette route renvoie des données dans un attribut nommé "Country". La valeur sélectionnée d'un attribut sera enregistrée dans le champ "my_country" (indiqué par autocomplete.outputs).

    Déclaration de l'aide à la saisie

    {
        "title": "Aide basique custom",
        "type": "Demande de renseignement",
        "structure": [
            {
                "label": "Localisation",
                "name": "my_fr_ident",
                "type": "frame",
                "content": [
                    {
                        "label": "Un pays",
                        "name": "my_country",
                        "type": "text",
                        "autocomplete": {
                            "url": "/my/countries/",
                            "outputs": {
                                "my_country": "Country"
                            }
                        }
                    }
                ]
            }
        ]
    }

    Résultat : Sélecteur sur le champ

    Valeurs sélectionnables dans le formulaire

    # Exemple : aide à la saisie à plusieurs sorties et une entrée

    Cette exemple montre comme réaliser une aide à la saisie permettant à un champ de choisir un utilisateur parmi un groupe donné.

    L'aide à la saisie nécessite 3 déclarations :

    1. La déclaration de la configuration de l'aide à la saisie dans le Smart Form structure.<field>.autocomplete (référence l'url de la route et les retours)
    2. La déclaration de la route : /my/users/ (référence la classe PHP)
    3. Le code de la classe PHP (My\AutoUsers) de la route (qui retourne les données indexées)

    Déclaration de la route `/my/users/` . Fichier `src/config/SmartDataEngine/myAutocompletes.xml`

    <?xml version="1.0"?>
    <sde:config xmlns:sde="https://platform.anakeen.com/4/schemas/sde/1.0">
        <sde:routes namespace="My">
            <sde:route name="Autocomplete:Users">
                <sde:priority>0</sde:priority>
                <sde:callable>My\AutoUsers</sde:callable>
                <sde:method>POST</sde:method>
                <sde:pattern>/my/users/</sde:pattern>
                <sde:description>Get countries</sde:description>
            </sde:route>
        </sde:routes>
    </sde:config>
    

    Classe PHP `My\AutoUsers` pour retourner les résultats (Fichier `vendor/My/AutoUsers.php`)

    <?php
    
    namespace My;
    
    use Anakeen\Core\SEManager;
    use Anakeen\Routes\Core\Lib\ApiMessage;
    use Anakeen\SmartAutocomplete;
    use SmartStructure\Fields\Igroup;
    use Psr\Http\Message\ResponseInterface as Response;
    use Psr\Http\Message\ServerRequestInterface as Request;
    
    /**
     * Class AutoUsers
     *
     * Données d'entrée :
     *  - "userGroup" (identifiant du groupe)
     * Données retournées :
     *  - "login"
     *  - "account"
     *  - "accountId"
     *  - "mail"
     */
    class AutoUsers
    {
        public function __invoke(Request $request, Response $response, $args)
        {
            $autocomplete = new SmartAutocomplete($request, $response);
    
            $filter = $autocomplete->getFilterValue();
            $inputGroup = $autocomplete->getInputValue("userGroup");
    
    
            $searchAccount = new \Anakeen\Accounts\SearchAccounts();
            $searchAccount->setTypeFilter(\Anakeen\Accounts\SearchAccounts::userType);
            if ($filter !== null) {
                $searchAccount->addFilter("lastname ~* '%s' OR login ~* '%s'", preg_quote($filter), preg_quote($filter));
            }
            $group=null;
            if ($inputGroup) {
                $group = SEManager::getDocument($inputGroup);
                if ($group) {
                    $searchAccount->addGroupFilter($group->getRawValue(Igroup::us_login));
                }
            }
            $searchAccount->setSlice(50);
    
            $groupsData = [];
            foreach ($searchAccount->search() as $currentAccount) {
                /** @var $currentAccount \Anakeen\Core\Account */
                $groupsData[] = [
                    "login" => $currentAccount->login,
                    "account" => [
                        "value" => $currentAccount->fid,
                        "displayValue" => $currentAccount->getAccountName()
                    ],
                    "accountId" => $currentAccount->id,
                    "mail" => $currentAccount->mail
                ];
            }
            $autocomplete->setEntryData($groupsData);
            $autocomplete->setEntryLabel("<span>{{login}}(<i>{{mail}}</i>)</span>");
    
            if (!$groupsData) {
                $autocomplete->setError("Aucun utilisateur trouvé");
            }
    
            if ($group) {
                $autocomplete->addMessage(new ApiMessage(sprintf("Utilisateurs du groupe \"%s\"", $group->getTitle())));
            }
            return $autocomplete->getResponse();
        }
    }
    

    L'exemple ci-dessous indique une aide à la saisie sur le champ "my_user". Elle référence la route /my/users/. Cette route renvoie des données dans 4 attributs nommés "login", "account", "accountId", "mail". Seules deux de ces valeurs ("mail" et "account") sont utilisées comme indiqué dans autocomplete.outputs. La valeur "account" est une valeur complexe car elle référence un type "docid" où la valeur brute est différente de la valeur affichée.

    La route utilise une donnée d'entrée "userGroup", cette donnée est celle du champ "my_group" (indiqué par autocomplete.inputs).

    Déclaration de l'aide à la saisie

    {
        "title": "Aide sur les utilisateurs",
        "type": "Demande de renseignement",
        "structure": [
            {
                "label": "Identification",
                "name": "my_fr_ident",
                "type": "frame",
                "content": [
                    {
                        "label": "Groupe",
                        "name": "my_group",
                        "type": "account",
                        "needed": true,
                        "options": {
                            "match": "group"
                        }
                    },
                    {
                        "label": "Utilisateur du groupe",
                        "name": "my_users",
                        "type": "docid",
                        "autocomplete": {
                            "url": "/devdata/users/",
                            "inputs": {
                                "my_group": "userGroup"
                            },
                            "outputs": {
                                "my_users": "account",
                                "my_email": "mail"
                            }
                        }
                    },
                    {
                        "label": "Adresse de courriel",
                        "name": "my_email",
                        "type": "text",
                        "display": "read"
                    }
                ]
            }
        ],
        "renderOptions": {
            "fields": {
                "my_fr_ident": {
                    "responsiveColumns": [
                        {
                            "number": 2,
                            "minWidth": "50rem",
                            "grow": true
                        }
                    ]
                }
            }
        }
    }

    Résultat : Sélecteur sur le champ

    Valeurs sélectionnables dans le formulaire

    # config.renderOptions(Smart Form RenderOptions)

    Cette partie permet de configurer l'aspect du formulaire à l'aide des options de rendu des Smart Fields.

    Les options peuvent être appliquées à un champ particulier ou pour un type de champ particulier ou de façon générale pour les options communes à tous les champs.

    Configuration par champs

    {
      "title": "Mon formulaire personnalisé",
      "renderOptions": {
        "fields": {
          "my_title": {
            "description": {
              "collapsed": false,
              "htmlContent": "<p>Décrire ici votre requête</p>",
              "htmlTitle": "<h3>Objet de la demande</h3>",
              "position": "top"
            },
            "labelPosition": "none",
            "placeHolder": "Indiquer l'objet de votre requête"
          },
          "my_firstframe": {
            "responsiveColumns": [
              {
                "number": 2,
                "minWidth": "50rem",
                "maxWidth": "70rem",
                "grow": true
              },
              {
                "number": 3,
                "minWidth": "70rem",
                "maxWidth": null,
                "grow": true
              }
            ]
          },
          "my_level": {
            "editDisplay": "vertical"
          },
          "my_comment": {
            "ckEditorInline": true,
            "toolbar": "Simple"
          }
        }
      },
      "structure": [
        {
          "label": "Informations",
          "name": "my_firstframe",
          "type": "frame",
          "content": [
            {
              "label": "Title",
              "name": "my_title",
              "type": "text",
              "needed": true
            },
            {
              "label": "Date de rédaction",
              "name": "my_date",
              "type": "date"
            },
            {
              "label": "Criticité",
              "name": "my_level",
              "type": "enum",
              "enumItems": [
                {
                  "key": "low",
                  "label": "Faible"
                },
                {
                  "key": "medium",
                  "label": "Moyen"
                },
                {
                  "key": "hight",
                  "label": "Élevé"
                }
              ]
            },
            {
              "label": "Remarques",
              "name": "my_comment",
              "type": "htmltext"
            }
          ]
        }
      ]
    }

    Résultat : Un formulaire responsive de 1 à 3 colonnes

    Structure du formulaire

    Exemple avec les propriétés types et common sur les renderOptions.

    Configuration générale et par type

    {
      "title": "Libellé sur le dessus",
      "renderOptions": {
        "common": {
          "labelPosition": "left"
        },
        "types": {
          "enum": {
            "editDisplay": "vertical"
          },
          "htmltext": {
            "toolbar": "Basic",
            "labelPosition": "up",
            "height": "21rem"
          }
        }
      },
      "structure": [
        {
          "label": "Informations",
          "name": "my_firstframe",
          "type": "frame",
          "content": [
            {
              "label": "Title",
              "name": "my_title",
              "type": "text",
              "needed": true
            },
            {
              "label": "Date de rédaction",
              "name": "my_date",
              "type": "date"
            },
            {
              "label": "Criticité",
              "name": "my_level",
              "type": "enum",
              "enumItems": [
                {
                  "key": "low",
                  "label": "Faible"
                },
                {
                  "key": "medium",
                  "label": "Moyen"
                },
                {
                  "key": "hight",
                  "label": "Élevé"
                }
              ]
            },
            {
              "label": "Remarques",
              "name": "my_comment",
              "type": "htmltext"
            }
          ]
        }
      ]
    }

    Résultat : Libellés sont sur le dessus des champs

    Structure du formulaire

    Propriété Scope Description
    labelPosition * [up, left, none] : position du libellé par rapport à la valeur
    attributeLabel * Remplace le Libellé défini dans la structure
    description * Indique une description
    > description.collapsed * Indique si la description doit être repliée
    > description.htmlContent * Titre de la description
    > description.htmlTitle * Contenu de la description
    > description.position * [top, right, bottom, left, topLabel, topValue, bottomLabel, bottomValue, click] Placement de la description
    placeHolder text, date, time, timestamp, longtext, int, double, money Affiche le texte si la valeur est vide (display "write" seulement)
    displayDeleteButton * (bool) Affiche le bouton pour effacer le champ (true par défaut)
    inputHtmlTooltip * (html) Affiche un message au focus du champ (display "write" seulement)
    template * (html) Template de représentation d'un champ
    translatedLabels *, file, enum Textes traduisibles utilisés dans l'affichage du champ
    buttons * (array) Liste de boutons spécifiques, un bouton est caractérisé par les propriétés suivantes
    > buttons[n].htmlContent * (html) Libellé du bouton
    > buttons[n].url * Url
    > buttons[n].target * Target de l'url (_self, _dialog, ...)
    > buttons[n].title * (html) Texte affiché au survol
    > buttons[n].windowHeight * Hauteur de la fenêtre ouverte
    > buttons[n].windowWidth * Largeur de la fenêtre ouverte
    > buttons[n].windowTitle * Titre de la fenêtre ouverte
    transpositionWidth array Largeur à partir de laquelle le tableau est affiché en mode transposé
    rowCountThreshold array Affichage du nombre de rangées
    rowAddDisable array (bool) Désactive la possibilité d'ajouter des rangées dans le tableau (false par défaut)
    rowDelDisable array (bool) Désactive la possibilité d'enlever des rangées dans le tableau (false par défaut)
    rowMoveDisable array (bool) Désactive la possibilité de déplacer des rangées dans le tableau (false par défaut)
    rowMinLimit array (int) Nombre minimum de rangées non supprimable pour un tableau
    rowMaxLimit array (int) Nombre maximum de rangées que l'utilisateur peut avoir pour un tableau
    rowMinDefault array (int) Nombre minimum de rangées affichées à l'initialisation pour un tableau
    decimalPrecision double (int) Nombre de décimales à prendre en compte
    editDisplay enum Type d'affichage ("list", "horizontal", "vertical", "bool" )
    collapse frame Si le cadre doit être replié ou non : "expand", "collapse" , "none"
    responsiveColumns frame Règles du multi-colonnes en fonction de la largeur du cadre

    Certaines options ne sont applicables qu'à l'ensemble du formulaire. Il faut dans ce cas utiliser le mot clef document.

    {
      "title": "Formulaire",
      "renderOptions": {
        "document": {
          "stickyTabs": "auto",
          "tabPlacement": "left"
        }
      }
    }
    
    Propriété Description
    tabPlacement [top, left, topProportional] : position du libellé par rapport à la valeur
    stickyTabs Coller les onglets en haut du formulaire lors d'un scroll vertical

    # config.menu (Smart Form Menu)

    La propriété menu du Smart Form permet d'ajouter des menus dans la formulaire. Trois types d'élément de menu sont disponibles :

    • itemMenu : Élément de menu simple
    • listMenu : Menu déroulant
    • separatorMenu : Séparateur de menu

    Les menus permettent d'envoyer des événements avec l'url #actions/<eventId>. Si l'url commence par #actions/ alors la méthode $on permet de capturer le click.

    Par défaut, les éléments de menu sont alignés à droite. Pour aligner un élément de menu à gauche, il faut utiliser la classe css menu--left (dans la propriété htmlAttribute).

    Propriété Type Description
    id string (obligatoire) Identifiant du menu
    type: string "listMenu" , "itemMenu" ,"separatorMenu";
    beforeContent string Fragment html, utilisé souvent pour afficher une icône
    htmlAttributes object Attributs html à ajouter à la DOM ({attrName : attrValue, ...})
    label string Texte brut à afficher
    htmlLabel string Texte HTML à afficher
    tooltipLabel string Texte du tooltip au survol
    tooltipPlacement string Placement du tooltip ["top" , "bottom" , "right", "left"];
    tooltipHtml boolean (false par défaut) Le texte du tooltip ne doit pas être encodé
    visibility string "visible" "hidden" ,"disabled"
    important boolean (false par défaut) le menu ne doit pas être placé dans le menu "Autre" même s'il n'y a plus de place
    iconUrl string Url d'une image pour l'icône du menu (placé à gauche du texte)
    target string Target window de la cible
    targetOptions.title string Titre de la dialog window si target = _dialog
    target.windowWidth string Largeur de la fenêtre
    target.windowHeight string Hauteur de la fenêtre
    confirmationText string Libellé de la confirmation, s'il est non vide cela indique qu'une confirmation sera demandée
    confirmationOptions.cancelButton string Libellé du bouton d'annulation
    confirmationOptions.confirmButton string Libellé du bouton de confirmation
    confirmationOptions.windowWidth string Largeur de la fenêtre de confirmation (32rem par défaut)
    confirmationOptions.windowHeight string Hauteur de la fenêtre de confirmation (18rem par défaut)

    Configuration de la barre de menu avec bouton de sauvegarde.

    {
      "title": "Menu Formulaire",
      "type": "Invitation",
      "icon": "/api/v2/images/assets/sizes/24x24c/se-image.png",
      "menu": [
        {
          "id": "special",
          "beforeContent": "<div class=\"fa fa-superpowers\" />",
          "htmlAttributes": {
            "class": "menu--left"
          },
          "label": "Spécial",
          "type": "itemMenu",
          "url": "#action/my.superpower"
        },
        {
          "id": "image",
          "type": "itemMenu",
          "label": "Info",
          "iconUrl": "/Images/info.svg",
          "url": "/api/v2/smart-elements/87527/images/img_file/-1/sizes/800.png?c=20190904095344",
          "target": "_dialog",
          "targetOptions": {
            "title": "Régate",
            "windowWidth": "800px",
            "windowHeight": "450px"
          }
        },
        {
          "id": "mylist",
          "beforeContent": "<div class=\"fa fa-heart\" />",
          "htmlAttributes": {
            "class": "menu--left"
          },
          "label": "Options",
          "type": "listMenu",
          "content": [
            {
              "id": "message",
              "type": "itemMenu",
              "label": "Send message",
              "htmlLabel": "",
              "beforeContent": "<div class=\"fa fa-telegram\" />",
              "url": "#action/my.sendmessage"
            },
            {
              "id": "detail",
              "type": "itemMenu",
              "label": "Plus d'information",
              "beforeContent": "<div class=\"fa fa-binoculars\" />",
              "url": "#action/my.extrainfo"
            },
            {
              "id": "image",
              "type": "itemMenu",
              "label": "Voile",
              "iconUrl": "/api/v2/smart-elements/87527/images/img_file/-1/sizes/48x48c.png?c=20190904095344",
              "url": "/api/v2/smart-elements/87527/images/img_file/-1/sizes/800.png?c=20190904095344",
              "target": "_dialog",
              "targetOptions": {
                "title": "Régate",
                "windowWidth": "800px",
                "windowHeight": "450px"
              }
            }
          ]
        },
        {
          "id": "submit",
          "beforeContent": "<div class=\"fa fa-save\" />",
          "iconUrl": "",
          "important": false,
          "label": "Soumettre",
          "target": "_self",
          "type": "itemMenu",
          "url": "#action/document.save",
          "visibility": "visible"
        },
        {
          "id": "reset",
          "htmlLabel": "<span style='color:orange;font-weight:bold'>Réinitialisation</span>",
          "iconUrl": "",
          "confirmationText": "<h1>Attention <h1><h2>Phase de réinitialisation en approche</h2>",
          "confirmationOptions": {
            "cancelButton": "Non non",
            "confirmButton": "Oui je veux réinitialiser le système",
            "windowWidth": "40rem",
            "windowHeight": "17rem"
          },
          "target": "_self",
          "type": "itemMenu",
          "url": "#action/document.save",
          "visibility": "visible"
        }
      ],
      "structure": [
        {
          "name": "my_firstframe",
          "label": "My first frame",
          "type": "frame",
          "content": [
            {
              "label": "Title",
              "name": "my_title",
              "type": "text",
              "needed": true
            },
            {
              "label": "Date de l'événement",
              "name": "my_date",
              "type": "date"
            },
            {
              "label": "Remarques",
              "name": "my_comment",
              "type": "htmltext"
            }
          ]
        }
      ]
    }

    Résultat : Barre de menu personnalisée

    Barre de menu du formulaire

    # config.values (Smart Form Values)

    Les valeurs sont indiquées en utilisant le nom du smart field. La notation courte de la valeur est juste une chaîne de caractères. La notation longue permet de différencier la valeur affichée de la valeur brute.

    Affectation de valeurs simples

    {
      "title": "Valeurs",
      "type": "Invitation",
      "icon": "/api/v2/images/assets/sizes/24x24c/se-image.png",
      "structure": [
        {
          "label": "Caractéristiques",
          "name": "my_frame",
          "type": "frame",
          "content": [
            {
              "label": "Title",
              "name": "my_title",
              "type": "text",
              "needed": true
            },
            {
              "label": "Date de rédaction",
              "name": "my_date",
              "type": "date"
            },
            {
              "label": "Remarques",
              "name": "my_comment",
              "type": "htmltext"
            },
            {
              "label": "Criticité",
              "name": "my_level",
              "type": "enum",
              "enumItems": [
                {
                  "key": "low",
                  "label": "Faible"
                },
                {
                  "key": "medium",
                  "label": "Moyen"
                },
                {
                  "key": "hight",
                  "label": "Élevé"
                }
              ]
            }
          ]
        }
      ],
      "values": {
        "my_date": "2019-07-24",
        "my_title": "Hello world",
        "my_level": "medium",
        "my_comment": "<p>Ursidae</p>\n    <p>\n <img alt=\"Description de cette image, également commentée ci-après\"  src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/8/8a/Ursus_arctos_Dessin_ours_brun_grand.jpg/290px-Ursus_arctos_Dessin_ours_brun_grand.jpg\" style=\"height: 182px; width: 290px; float: right;\"></p><p><a href=\"https://fr.wikipedia.org/wiki/Ours_brun\">Ours brun</a>&nbsp;(<em>Ursus arctos</em>)</p>"
      }
    }
    

    Résultat : Valeurs dans le formulaire

    Valeurs préinitialisées dans le formulaire

    Les valeurs étendues permettent de définir complètement les caractéristiques de champs plus complexes comme les docid ou les file.

    Affectation de valeurs étendues

    {
      "title": "Valeurs étendues",
      "type": "Invitation",
      "icon": "/api/v2/images/assets/sizes/24x24c/se-image.png",
      "structure": [
        {
          "label": "Caractéristiques",
          "name": "my_frame",
          "type": "frame",
          "content": [
            {
              "label": "Title",
              "name": "my_title",
              "type": "text",
              "needed": true
            },
            {
              "label": "Facture",
              "name": "my_bill",
              "type": "docid",
              "typeFormat": "DEVBILL"
            },
            {
              "label": "Photo",
              "name": "my_picture",
              "type": "image"
            },
            {
              "label": "Criticité",
              "name": "my_level",
              "type": "enum",
              "enumItems": [
                {
                  "key": "low",
                  "label": "Faible"
                },
                {
                  "key": "medium",
                  "label": "Moyen"
                },
                {
                  "key": "hight",
                  "label": "Élevé"
                }
              ]
            }
          ]
        }
      ],
      "values": {
        "my_title": "Hello world",
        "my_bill": {
          "value": 98137,
          "displayValue": "Bill 0018"
        },
        "my_picture": {
          "creationDate": "2019-09-04 09:53:44",
          "displayValue": "regatta-1049741_1280.jpg",
          "fileName": "regatta-1049741_1280.jpg",
          "icon": "/api/v2/images/assets/sizes/24x24c/mime/png/mime-image.png",
          "mime": "image/jpeg",
          "size": "399052",
          "thumbnail": "/api/v2/smart-elements/87527/images/img_file/-1/sizes/48x48c.png",
          "url": "/api/v2/smart-elements/87527/files/img_file/-1/regatta-1049741_1280.jpg?inline=true",
          "value": "image/jpeg|1856421439332325192|regatta-1049741_1280.jpg"
        }
      }
    }

    Résultat : Valeurs étendues

    Valeurs préinitialisées dans le formulaire

    # Événements

    Les événements du Smart Form sont les mêmes que les événements Smart Element.

    L'exemple ci-dessous intercepte les événements ready et smartFieldChange qui permettent d'interagir sur toute modification du formulaire. Le menu déclenche aussi des événements qui sont interceptés par actionClick et beforeSave

    <template>
      <div>
        <ank-smart-form ref="smartFormRef" @smartElementMounted="smartElementMounted" :config="json" />
      </div>
    </template>
    <script>
    
      import AnkSmartForm from "@anakeen/user-interfaces/components/lib/AnkSmartForm.esm";
      import "@anakeen/user-interfaces/components/scss/AnkSmartElement.scss";
    
      export default {
        components: {
          AnkSmartForm: () => AnkSmartForm
        },
        data: () => {
          return {
            json: {
              title: "Formulaire minimaliste",
              type: "Demande de renseignement",
              structure: [
                {
                  label: "Identification",
                  name: "my_fr_ident",
                  type: "frame",
                  content: [
                    {
                      label: "Objet de la requête",
                      name: "my_title",
                      type: "text"
                    }
                  ]
                }
              ],
              menu: [
                {
                  id: "special",
                  beforeContent: '<div class="fa fa-superpowers" />',
                  label: "Spécial",
                  type: "itemMenu",
                  url: "#action/my.superpower"
                },
                {
                  id: "submit",
                  beforeContent: '<div class="fa fa-save" />',
                  label: "Soumettre",
                  type: "itemMenu",
                  url: "#action/document.save"
                }
              ]
            }
          };
        },
        methods: {
          smartElementMounted: function() {
            this.$refs.smartFormRef.$on("ready", event => {
              console.log("The form is ready to be used");
            });
            this.$refs.smartFormRef.$on("smartFieldChange", (event, formProperties, field, values) => {
              console.log("Field", field.id, "has a new value", field.getValue().value);
              console.log("The previous value is", values.previous ? values.previous.value : "");
              this.$refs.smartFormRef.showMessage({
                message: "Smart Field " + field.id + " has changed.",
                htmlMessage: "<h2>" + field.getValue().value + "</h2>"
              });
            });
            this.$refs.smartFormRef.$on("actionClick", (event, data, options) => {
              console.log("action", options.eventId);
              if (options.eventId === "my.superpower") {
                alert("Super power actived");
              }
            });
    
            this.$refs.smartFormRef.$on("beforeSave", (event, data) => {
              // Submit button activated
              console.log("beforeSave", event, data);
            });
          }
        }
      };
    </script>
    

    ← Smart Element Tab Un exemple →