Native JS

Native JS permet d'exécuter du code JavaScript à l'intérieur d'un script Ninox et de partager avec lui des fonctions et des variables. Native JS peut ainsi accéder aux variables Ninox et appeler des fonctions locales comme globales.

image.png

Limites

Modifier une variable Ninox dans NativeJS n'a aucun effet sur la variable Ninox.

Le JavaScript n'est exécuté que localement. Ajouter du JavaScript à du code qui s'exécute sur le serveur reste sans effet. De même, appeler depuis un code exécuté sur le serveur une fonction globale qui contient du JavaScript reste sans effet.

Voyez ici les codes qui s'exécutent localement et ceux qui s'exécutent sur le serveur :

image.png

Syntaxe

Exécution

Pour signaler à Ninox que vous passez au JavaScript, il faut entourer le code de #{ ... }# :

#{ alert("hello world") }#;

Rappelez-vous que Ninox est un langage précompilé, qui doit connaître à l'avance le type de chaque variable et de chaque fonction. Il en va de même pour Native JS : vous devez indiquer le type renvoyé par le code JavaScript. Par défaut, Native JS renvoie du texte, mais vous pouvez préciser le type de variable à renvoyer en l'indiquant tout au début du code, avec la notation :[type].

Valeur de retour

#{:text return "hello world"}#;

Les types possibles sont les mêmes que pour les appels de fonctions : text, number, date, datetime, time, timeinterval, appointment, boolean, html, color, icon, email, phone, location, file, user et any.

Types tableau

Pour renvoyer un tableau, utilisez la syntaxe suivante :

#{:number(array) return [1,2,3] }#;

Types enregistrement

Pour renvoyer des enregistrements, utilisez le nom de la table suivi de nid ou rid :

Si vous utilisez nid, vous devez renvoyer un tableau de valeurs texte contenant l'identifiant complet de l'enregistrement, c'est-à-dire l'identifiant de la table + le numéro de l'enregistrement :

#{:nid(customer) return ['A1','A2','A3'] }#

Si vous utilisez rid, vous devez renvoyer le numéro de l'enregistrement :

#{:rid(customer) return [1,2,3] }#

Pour les noms de tables composés, n'ajoutez pas de comme dans Ninox : utilisez simplement le nom complet de la table :

#{:rid(my long name table) return [1,2,3] }#

Avec cette syntaxe, Native JS renvoie des variables qui se comportent exactement comme du code Ninox. Vous pouvez donc employer la syntaxe suivante comme s'il s'agissait d'un select :

(#{:rid(customer) return [1,2,3] }# order by 'Last Name').'First Name';

image.png

Modification d'un enregistrement

Les variables de type enregistrement sont transmises au format JSON, avec une paire clé-valeur pour chaque champ de l'enregistrement.

var r := first(select Customer);
#{:text return r['First Name'] }#;

Ici, le contenu de la variable r en JavaScript ressemble à ceci :

{
 "Created on": 1648910817206,
 "Id": "A1",
 "Last modified": 1714817525840,
 "Modified by": "7zBqhAKXxfQAPmH7Y",
 "First Name": "Sofia",
 "Last Name": "Young",
 "Company": "Kollwitz GmbH",
 "Postal Code": "12345",
 "City": "New Jersey",
 "Address": "11,South Commerce Street",
 "Email": "sofi@kollwitz-gmbh.com",
 "Customer No": "K0001",
 "Title": "2",
 "Invoices": [
  1,
  16,
  17
 ],
 "Photo": "shutterstock_307218608.jpg",
 "Category": "1",
 "Position": "Marketing head",
 "Checked": true,
 "ID": "A1",
 "id": "A1"
}

Important

Selon que le code s'exécute dans l'application Mac ou sur le web, la casse de l'ID peut varier.
Pour parer à cela et éviter les conflits entre plateformes, l'ID est répété dans toutes les variantes de casse possibles.

Modifier l'enregistrement en JavaScript ne le met pas à jour dans Ninox.

Exécution asynchrone

Il est parfois utile de synchroniser l'exécution du code Ninox avec celle du JavaScript.
Par exemple, avec une minuterie, il importe que le code ne s'achève qu'après l'exécution de la minuterie.
Sans cette synchronisation, le code qui suit l'exécution du JavaScript se déroulerait immédiatement, avec des comportements inattendus à la clé.

Dans ce premier cas, la valeur « I don't know » est renvoyée immédiatement, et la fonction alert affiche le résultat avant même que la question ne soit posée à l'utilisateur.

var r:= #{:text
   setTimeout( () => {
      if (confirm("Are you ok ?"))
        return "of course";
      else
        return "Never !";
   }, 2000);
  return "I don't know";
}#;
alert( "Your answer is : "+r );

image.png

En passant en mode callback, la fonction alert de Ninox ne s'exécute qu'après que le code JavaScript a appelé la fonction de rappel, c'est-à-dire après que la question a été posée à l'utilisateur.

var r:= #{:text:callback
   setTimeout( () => {
      if (confirm("Are you ok ?"))
         callback( "of course" );
      else
        callback( "Never !" );
   }, 2000);
   return "I don't know";
}#;
alert( "Your answer is : "+r );

Enregistrement de l’écran 2025-03-03 à 11.46.26.gif

Appel de fonction

Il est possible d'appeler des fonctions Ninox depuis le JavaScript. La procédure peut être locale ou globale ; il suffit qu'elle se trouve dans la portée du code JavaScript.

function display( message : text ) do
    alert( message );
end;
#{ display('hello world') }#;

image.png

Pour récupérer la valeur de retour d'une fonction, il faut là encore passer par le mode callback (voir ci-dessus : Exécution asynchrone) :

function add( a : number, b : number ) do
    a + b;
end;

#{:number:callback
   add( 1, 2, (returnValue) => {
     callback( returnValue )
   })
}#;

image.png

Si vous n'avez aucun traitement à faire après l'appel de la procédure, vous pouvez passer directement la fonction de rappel en paramètre :

function add( a : number, b : number ) do
    a + b;
end;
#{:number:callback
   add( 1, 2, callback )
}#;

image.png

Manipuler enregistrements et fonctions

Si vous disposez d'une liste d'identifiants d'enregistrements, vous pouvez appeler une fonction Ninox pour modifier chaque enregistrement l'un après l'autre. Il suffit d'appeler la fonction en lui passant l'identifiant.

function setCustomerChecked( id : text, checked : boolean ) do
   var n := number(replacex(id, "\D",""));
   var rec := record( Customer, n );
   rec.Checked := checked;
end;
var c := select Customer;
var isChecked := not first(c).Checked;
#{
   c.forEach( v => { setCustomerChecked( v, isChecked ) } );
}#;
c.checked;

Erreurs d'exécution

Si une erreur d'exécution survient dans votre code, le texte du message d'erreur est renvoyé :

image.png