Mettre un coup de polish dans son appli shiny en utilisant une librairie JavaScript : l’exemple de sweetalert2

Author : Yohann Mansiaux
Categories : développement, shiny
Tags : javascript, shiny
Date :

Vous trouvez certains composants de {shiny} peu fonctionnels ou austères ? Vous cherchez à implémenter une fonctionnalité particulière dans votre appli mais celle-ci est absente de la boite à outils de {shiny} ? Jetez un oeil du côté du JavaScript !.

Le JavaScript est un langage de programmation très populaire qui est souvent utilisé pour ajouter des fonctionnalités à des pages web. Avec le HTML et le CSS, le JavaScript est un langage indispensable chez les développeurs Web. La taille de sa communauté d’utilisateurs fait que si vous cherchez à implémenter une fonctionnalité particulière, il y a de fortes chances que quelqu’un ait déjà eu le même besoin que vous et ait partagé son code !

Autre point positif (et indispensable pour nous dans le cas présent) : il est possible d’intégrer des librairies JavaScript dans une application {shiny} pour ajouter des fonctionnalités qui ne sont pas disponibles de base. En plus de cela, {golem} va nous aider à mettre tout ca en place.

Plus d’excuses pour reculer, en avant ! 🚀

J’ai pas le temps de lire : de quoi ca parle ?

  • Aller plus loin dans {shiny} en intégrant une librairie JavaScript c’est possible !
    • On prend l’exemple de sweetalert2, qui permet d’afficher des alertes plus jolies que celles de base
    • {golem} a plusieurs fonctions pour nous faciliter la vie pour intégrer des librairies JavaScript dans une app {shiny}
    • Cet exemple est plutôt simple. L’intégration de librairies est parfois plus complexe car certaines librairies sont mieux documentées que d’autres

Importer sweetalert2 dans une app {shiny} créée avec {golem}

Présentation de sweetalert2

  • sweetalert2 est une librairie JavaScript qui permet d’afficher des alertes plus jolies que celles de base
  • Elle est très bien documentée
  • Elle est très populaire (plus de 16000 “stars” sur GitHub à la date de publication de cet article)

Allons jeter un oeil aux possibilités offertes par sweetalert2 : https://sweetalert2.github.io/

 

Si vous cliquez sur “Show normal alert”, vous verrez une alerte classique alors qu’en cliquant sur “Show success message”, vous verrez une alerte sweetalert2.

La première a un design assez austère tandis que la seconde est plus moderne et plus agréable à l’oeil, elle saura probablement offrir une meilleure expérience utilisateur.

N’hésitez pas à jouer avec les différents types d’alertes proposés par sweetalert2 pour vous faire une idée de ce qu’il est possible de faire avec cette librairie en visitant la section d’exemples.

Ajouter les dépendances nécessaires à l’app {shiny}

Les sections qui vont suivre supposent que vous avez déjà créé une app {shiny} avec {golem}.

Si ce n’est pas encore le cas et que vous souhaitez en savoir plus sur {golem}, je vous invite à consulter la documentation officielle.

Pour ajouter sweetalert2 à votre app {shiny}, il va falloir trouver un moyen d’incorporer les fichiers nécessaires à son fonctionnement dans votre application.

Deux solutions s’offrent à vous :

  • Utiliser un “CDN” (Content Delivery Network) pour charger les fichiers depuis un serveur tiers. Le CDN va être l’équivalent d’un CRAN pour les librairies JavaScript. Concrètement, on va demander à notre application de pointer vers les sources de sweetalert2, hébergées sur un serveur distant.
  • Télécharger les fichiers nécessaires à son fonctionnement et les intégrer directement dans votre application. Si votre application a vocation à être utilisée sur une machine non reliée à Internet vous allez forcément devoir passer par cette étape.

Pas de panique ! Nous allons voir les 2 méthodes

Où trouver les éléments dont j’ai besoin ?

La documentation de sweetalert2 est très bien faite. Vous y trouverez toutes les informations nécessaires pour intégrer la librairie à votre application à partir de la section Download.

Malgré tout, il va falloir apprendre à repérer les éléments dont vous avez besoin pour intégrer sweetalert2 à votre application.

 

A la recherche du CDN

Dans la partie “Download & Install”, nous trouvons un lien vers le CDN de sweetalert2. C’est ce lien que nous allons devoir ajouter à notre application pour pouvoir utiliser la librairie.

 

Lorsque l’on clique sur le lien, on arrive sur une page qui ressemble à ça :

Ce qui va nous intéresser ici, c’est le lien qui se trouve dans la balise <script> et le lien qui se trouve dans la balise <link>. Le lien vers le fichier avec l’extension .js correspond au fichier JavaScript de sweetalert2. Le lien vers le fichier avec l’extension .css correspond au fichier de styles de sweetalert2.

Copions-les et retournons du côté de notre app !

Méthode 1 : Ajouter les dépendances à sweetalert2 via le CDN

Ouvrons le fichier R/app_ui.R de notre application et ajoutons les deux liens que nous avons copiés précédemment dans le corps de la fonction golem_add_external_resources().

golem_add_external_resources <- function() {
  add_resource_path(
    "www",
    app_sys("app/www")
  )
  tags$head(
    favicon(),
    bundle_resources(
      path = app_sys("app/www"),
      app_title = "golemsweetalert"
    ),
    # sweetalert2
    tags$script(src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js"),
    tags$link(href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.min.css",
              rel="stylesheet")
  )
}

On retrouve ici un appel à tags$script et un appel à tags$link correspondant respectivement aux balises <script> et <link> vues sur les liens fournis par le CDN.

On copie-colle les éléments en étant vigilant sur les noms de paramètres src, href et rel et en pensant à les séparer par des virgules. Nous passons en effet de code HTML (où les éléments sont séparés par des espaces) à du code R.

Méthode 2 : Ajouter les dépendances à sweetalert2 en local

Les liens identifiés précédemment vont également nous être utiles pour télécharger les fichiers nécessaires à l’utilisation de sweetalert2.

Le lien vers le fichier avec l’extension .js va être passé à la fonction golem::use_external_js_file() tandis que le lien vers le fichier avec l’extension .css va être passé à la fonction golem::use_external_css_file().

Pour en conserver une trace, nous enregistrons les commandes suivantes dans le fichier dev/02_dev.R dans la section “External resources”.

golem::use_external_js_file("https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js")
golem::use_external_css_file("https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.min.css")

Les deux fichiers sont maintenant présents dans le dossier inst/app/www du projet de notre application.

Tout est ok, on peut continuer notre bout de chemin 👍.

Comment savoir si sweetalert2 est bien importé dans mon app {shiny} ?

Pour vérifier que sweetalert2 est bien importé dans notre application, nous ouvrons notre navigateur puis la console de développement.

Avant cela, lançons notre app avec golem::run_dev() !

NB : Les captures suivantes ont été réalisées avec le navigateur Google Chrome.

Sur la fenêtre de notre application, nous faisons un clic droit puis sélectionons “Inspecter”. Dans la nouvelle fenêtre qui va s’ouvrir, on choisit l’onglet “Console” puis on tape la commande Swal.fire("Hello sweetalert2 !"). Cette console permet d’exécuter du code JavaScript, qui sera interprété par notre navigateur.

Si tout s’est bien passé, nous devrions voir une alerte sweetalert2 apparaître ! Dans le cas contraire nous aurions peut-être un message d’erreur en rouge (qu’il va falloir apprendre à décrypter, comme avec une console R :-)).

Ca marche ! 🎉

Comment j’ai su qu’il fallait taper Swal.fire(" .... ") ?

Grâce à la documentation ! En allant sur la page de sweetalert2, on trouve de nombreux exemples d’utilisation de la librairie. En l’occurrence, pour afficher une alerte, il faut utiliser la fonction Swal.fire(). Comme pour l’apprentissage d’un nouveau package R, on voit que la documentation (quand elle existe …) a une importance primordiale pour la prise en main des librairies JavaScript.

Créer une alerte sweetalert2 dans notre app {shiny}

Maintenant que nous avons importé sweetalert2 dans notre application et vérifié que l’import s’était bien passé, nous allons créer une fonction qui va nous permettre d’appeler sweetalert2 à partir de notre application.

Nous allons tenter d’incorporer l’alerte “A title with a text under” dans notre application.

Trois éléments vont pouvoir être paramétrés ici :

  • Le titre de l’alerte
  • Le texte de l’alerte
  • Le type d’alerte (success, error, warning, info, question) et son icone associée

Nous imaginons bien comment modifier ces éléments directement dans le code JavaScript mais nous ne savons pas encore comment créer cette alerte via du code R.
C’est parti !

Créer un fichier JavaScript pour appeler sweetalert2

Pour appeler sweetalert2 à partir de notre application, nous allons créer un fichier JavaScript dans lequel nous allons écrire une fonction qui va nous permettre de créer une alerte.

Pour cela, nous allons créer un fichier inst/app/www/sweet_alert.js dans lequel nous allons coller le code permettant de créer l’alerte sélectionnée précédemment. Nous pourrions créer ce fichier manuellement, mais nous allons profiter des fonctionnalités offertes par {golem} pour le faire.

Rendez-vous dans le fichier dev/02_dev.R ! Nous ajoutons la ligne suivante dans la section “External Resources” :

golem::add_js_handler("sweet_alert")

Le nom du fichier importe peu, mais il est important de respecter l’extension .js pour que le fichier soit bien interprété comme du code JavaScript. Nous aurions pu également créer des sous-dossiers si nous avions eu de nombreux imports et fichiers à gérer. Le seul pré-requis est que tout soit situé dans le répertoire inst/app/www.

Nous obtenons un squelette un peu étrange, qui va en fait être le squelette d’une fonction JavaScript, utilisable dans notre application {shiny} :

$( document ).ready(function() {
  Shiny.addCustomMessageHandler('fun', function(arg) {
  })
});

Nous allons substituer le terme 'fun' par le nom de la fonction que l’on voudra appeler dans notre application {shiny} et ajouter le code permettant de créer l’alerte sweetalert2.

On obtient donc le code suivant :

$( document ).ready(function() {
  Shiny.addCustomMessageHandler('alert_title_and_text_under', function(arg) {
    Swal.fire({
      title: "The Internet?",
      text: "That thing is still around?",
      icon: "question"
    });
  })
});

Nos paramètres “title”, “text” et “icon” sont toujours fixés en dur, il faut trouver un moyen de les faire varier en fonction des choix de l’utilisateur. On peut remarquer l’existence d’un paramètre “arg” dans la fonction Shiny.addCustomMessageHandler(). C’est ce paramètre qui va nous permettre de transmettre des informations à notre fonction JavaScript.

Modifions notre code :

$( document ).ready(function() {
  Shiny.addCustomMessageHandler('alert_title_and_text_under', function(arg) {
    Swal.fire({
      title: arg.title,
      text: arg.text,
      icon: arg.icon
    });
  })
});

La notation à utiliser ici sera arg.nom_du_parametre pour accéder aux valeurs transmises par notre application {shiny}. La notation avec le “.” est une convention JavaScript pour accéder aux propriétés d’un objet. Pour faire le parallelle avec R, c’est un peu comme si on faisait arg$nom_du_parametre.

Côté JavaScript tout est bon ! Retournons maintenant sur nos terres plus familières, le monde du langage R !

Et si on testait tout ça dans notre app {shiny} (ENFIN !) ?

Côté UI, on ajoute un bouton dans le fichier R/app_ui.R :

app_ui <- function(request) {
  tagList(
    # Leave this function for adding external resources
    golem_add_external_resources(),
    # Your application UI logic
    fluidPage(
      h1("golemsweetalert"),
      actionButton(inputId = "show_alert",
                   label = "Alert demo")
    )
  )
}

Côté serveur, on ajoute un observeEvent() dans le fichier R/app_server.R, qui va appeler notre fonction JavaScript de génération d’une alerte lorsque l’utilisateur clique sur le bouton “Alert demo”.

Encore une fois, {golem} va nous faciliter la tâche ! Nous allons passer par la fonction golem::invoke_js() pour appeler notre fonction JavaScript.

Deux paramètres sont passés à golem::invoke_js():

  • le premier paramètre correspond au nom de la fonction JavaScript à appeler
  • le second paramètre correspond à une liste de paramètres, l’équivalent côté JavaScript de notre objet arg qui va être utilisé pour transmettre les informations nécessaires à la création de l’alerte sweetalert2. Les noms utilisés dans la liste ici doivent correspondre aux noms utilisés dans la fonction JavaScript pour le paramètre arg (“title”, “text” et “icon”).
app_server <- function(input, output, session) {
  # Your application server logic
  observeEvent(
    input$show_alert,{
      golem::invoke_js(
        "alert_title_and_text_under",
        list(
          title = "Title",
          text = "Text",
          icon = "success"
        ))
    }
  )
}

On lance un appel à golem::run_dev() pour voir notre application en action !

Ca marche ! 🍾

Pour rendre le tout plus élégant, nous pouvons créer une fonction R qui réalisera l’appel à golem::invoke_js().

Créer une fonction R pour appeler sweetalert2

Nous allons passer par {golem} pour créer notre fonction. Pour cela, nous allons ajouter la ligne suivante dans le fichier dev/02_dev.R de notre application :

golem::add_fct("create_alert_title_and_text_under")

On obtient un fichier R/fct_create_alert_title_and_text_under.R dans lequel nous allons pouvoir écrire notre fonction, qui va faire appel au code JavaScript créé à l’étape précédente.

#' create_alert_title_and_text_under
#'
#' @description Creates an alert with a title, a text and an icon
#' @param title alert title
#' @param text alert text
#' @param icon alert icon
#' @return side effect : creates an alert
#'
#' @noRd
create_alert_title_and_text_under <- function(
    title = "Title",
    text = "Text",
    icon = "success"
    ) {
  golem::invoke_js(
    "alert_title_and_text_under",
    list(
      title = title,
      text = text,
      icon = icon
    )
  )
}

Modifions également les fichiers R/app_ui.R et R/app_server.R pour pouvoir définir les paramètres de notre alerte grâce à des choix effectués par l’utilisateur.

app_ui <- function(request) {
  tagList(
    # Leave this function for adding external resources
    golem_add_external_resources(),
    # Your application UI logic
    fluidPage(
      h1("golemsweetalert"),
      textInput(inputId = "title",
                label = "title"),
      textInput(inputId = "text",
                label = "text"),
      radioButtons(inputId = "icon",
                   label = "icon",
                   choices = c("warning", "error", "success", "info", "question")),
      actionButton(inputId = "show_alert",
                   label = "Alert demo")
    )
  )
}

Pour définir la liste des “choices” possibles du radioButtons, nous avons repris les valeurs possibles pour le paramètre icon de sweetalert2, comme indiqué dans la documentation officielle : https://sweetalert2.github.io/#icon.

app_server <- function(input, output, session) {
  # Your application server logic
  observeEvent(
    input$show_alert,{
      create_alert_title_and_text_under(
        title = input$title,
        text = input$text,
        icon = input$icon
      )
    }
  )
}

Lançons enfin un appel à golem::run_dev() :

Bravo ! 👏

Et un exemple plus compliqué ?

En suivant le cheminement précédent, c’est relativement aisé d’ajouter des éléments supplémentaires dans une alerte, comme par exemple une image ou des boutons de confirmation / annulation. Une plongée un peu plus profonde dans la documentation de sweetalert2 permettra de comprendre comment ajouter ces éléments.

Voici en image ce qu’il est possible de réaliser :

Vous voulez en savoir plus ? Rendez vous sur le code source de ce projet.

Conclusion

  • Incorporer des librairies JavaScript dans une application {shiny} est possible
  • {golem} facilite grandement la tâche
  • C’est relativement facile quand la librairie est bien documentée
  • Il est important de bien lire la documentation de la librairie que l’on souhaite intégrer (mais c’est aussi vrai en R !)
  • L’inspecteur présent dans le navigateur est un outil très utile pour vérifier que tout se passe bien
  • Pour intégrer des librairies plus complexes il faudra probablement des compétences minimales en JavaScript

Si vous voulez d’autres exemples de l’utilisation de sweetalert2, mais aussi d’autres librairies JavaScript (Grid.js et Chart.js), vous pouvez consulter l’application mycomicslibrary et jeter un oeil à son code source.

Merci d’avoir suivi ce tutoriel et amusez-vous bien dans le monde merveilleux du JavaScript ! 🚀


À propos de l'auteur

Yohann Mansiaux

Yohann Mansiaux

Data Scientist au pays des m'R'veilles


Comments


Also read