Natywny JS
Natywny JS pozwala wykonywać kod JavaScript wewnątrz skryptu Ninox oraz dzielić z nim funkcje i zmienne. Dzięki temu natywny JS może odczytywać zmienne Ninox i wywoływać funkcje zadeklarowane w tej samej formule; funkcje kodu globalnego wywołuje się natomiast przez ninext.callNinoxFunction (zob. niżej, „Wywołanie funkcji kodu globalnego”).
Natywny JS jest domyślnie aktywny; wyłącza się go w panelu Ustawienia Ninext, w sekcji „Integracja JavaScript” (Natywny JavaScript).

Ograniczenia
Zmiana zmiennej Ninox w natywnym JS nie wpływa na tę zmienną w Ninox.
JavaScript wykonuje się wyłącznie lokalnie. Dodanie JavaScriptu do kodu uruchamianego na serwerze nie daje żadnego efektu. Podobnie wywołanie funkcji globalnej zawierającej JavaScript z kodu wykonywanego na serwerze nie daje żadnego efektu. Od wersji 3.2.0 karta Błędy sygnalizuje blok umieszczony bezpośrednio w wyzwalaczu tabeli (po utworzeniu, po modyfikacji) lub w do as server.
Tutaj widać, które fragmenty kodu wykonują się lokalnie, a które na serwerze:

Składnia
Wykonanie
Aby wskazać Ninox, że przechodzą Państwo na JavaScript, należy zamknąć kod w #{ ... }#:
#{ alert("hello world") }#;Proszę pamiętać, że Ninox jest językiem prekompilowanym, który musi z góry znać typ każdej zmiennej i funkcji. To samo dotyczy natywnego JS: trzeba określić typ zwracany przez kod JavaScript. Domyślnie natywny JS zwraca tekst, ale mogą Państwo wskazać typ zwracanej zmiennej, podając go na samym początku kodu w notacji :[typ].
Adnotacja przylega do #{ bez żadnej spacji: #{:number …, a nie #{ :number …. Podobnie dwie adnotacje następują po sobie bez spacji (:text:callback). Ze spacją adnotacja nie zostaje rozpoznana: blok otrzymuje typ tekstowy, a adnotacja pozostaje w kodzie JavaScript, gdzie powoduje błąd składni.
Wartość zwracana
#{:text return "hello world"}#;Możliwe typy to: text, number, date, timestamp (data i godzina), time, timeinterval, appointment, boolean, html, color, icon, email, phone, location, file, user, json oraz any. Pełną listę, z choice, link, style i styled, proponuje Konsola (zob. niżej).
Uwaga
Datę z godziną opisuje się adnotacją :timestamp, natomiast parametr funkcji tego samego typu deklaruje się jako datetime. :datetime nie istnieje jako adnotacja: blok otrzymałby typ tekstowy. Od wersji 3.2.0 karta Błędy sygnalizuje nieznaną adnotację.
Daty, godziny i czasy trwania są przekazywane w milisekundach: zmienna Ninox tego typu trafia do JavaScriptu jako liczba, a blok :date lub :array(date) musi zwrócić milisekundy (to, co daje getTime() daty JavaScript).
Typy tablicowe
Aby zwrócić tablicę wartości, należy wskazać typ jej elementów za pomocą :array(type) (od wersji 3.2.0):
#{:array(number) return [1, 2, 3] }#;Możliwe są wszystkie typy proste: :array(text), :array(date), :array(any)…
Do wersji 3.1.2 włącznie można zwrócić wyłącznie tablicę typu any. Ten zapis pozostaje prawidłowy jako odpowiednik :array(any):
#{:any(array) return [1, 2, 3] }#;Zapis :number(array), przedstawiany dawniej na tej stronie, nie zwraca tablicy. Od wersji 3.2.0 sygnalizuje go karta Błędy.
Typy rekordowe
Aby zwrócić rekordy, należy użyć nid lub rid, po którym następuje nazwa tabeli w nawiasach:
Jeśli używają Państwo nid, trzeba zwrócić tablicę wartości tekstowych zawierających pełny identyfikator rekordu, czyli identyfikator tabeli + numer rekordu:
#{:nid(customer) return ['A1','A2','A3'] }#Jeśli używają Państwo rid, należy zwrócić numer rekordu:
#{:rid(customer) return [1,2,3] }#W przypadku nazw tabel złożonych z kilku słów nie należy dodawać ' jak w Ninox, lecz po prostu użyć pełnej nazwy tabeli:
#{:rid(my long name table) return [1,2,3] }#Dzięki tej składni natywny JS zwraca zmienne, które zachowują się tak samo jak w kodzie Ninox. Oznacza to, że można używać poniższej składni tak, jakby to był select:
(#{:rid(customer) return [1,2,3] }# order by 'Last Name').'First Name';
Pomoc przy wpisywaniu w Konsoli
Od wersji 3.2.0 Konsola pomaga zapisać blok:
- w adnotacji: po wpisaniu
:tuż po#{proponuje typy zwracane,array(type),nid(Table)irid(Table); po wpisaniu(ponidlubrid— listę tabel, a poarray— listę typów; drugi znak:proponuje modyfikatorycallbackiasync; - w JavaScripcie: autouzupełnianie proponuje zmienne i funkcje Ninox, które otrzymuje blok, w ich postaci JavaScript, a po kropce — składowe obiektu; w przypadku rekordu — nazwy jego pól (zob. „Autouzupełnianie JavaScriptu w blokach natywnych” na stronie Konsola).
Ta pomoc istnieje wyłącznie w Konsoli.
Co sprawdza Ninext
Od wersji 3.2.0 (beta). Karta Błędy kontroluje bloki
#{ … }#całej bazy, a Konsola — bloki kodu, który Państwo w niej piszą.
Sygnalizowane są:
- błąd składni JavaScript;
- nieznana adnotacja (taka jak
:datetime) lub tabela, której nie znaleziono w:nid(…)albo:rid(…): blok otrzymałby typ tekstowy; - blok z typem bez żadnego
returnalbo taki, w którym niektóre ścieżki nie docierają do żadnego: zwróciłby pustą wartość; - blok
:callbacklub:async, który nigdy nie wywołujecallback: formuła nigdy nie otrzymałaby wartości; - blok umieszczony bezpośrednio w wyzwalaczu tabeli (po utworzeniu, po modyfikacji) lub w
do as server, gdzie się nie wykonuje.
Modyfikacja rekordu
Zmienne typu rekordowego są przekazywane w formacie JSON, z parą klucz-wartość dla każdego pola rekordu.
var r := first(select Customer);
#{:text return r['First Name'] }#;Zawartość zmiennej r w JavaScripcie wygląda tutaj następująco:
{
"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"
}Obiekt ma ponadto klucz _node: rekord w postaci, w jakiej przechowuje go Ninox, z polami wskazanymi przez ich wewnętrzne identyfikatory.
Ważne
W zależności od tego, czy kod wykonuje się w aplikacji na Maca, czy w przeglądarce, ID może mieć różną wielkość liter.
Aby temu zaradzić i uniknąć konfliktów między platformami, ID jest powtarzane we wszystkich możliwych wariantach wielkości liter.
Modyfikacja rekordu w JavaScripcie nie aktualizuje go w Ninox.
Wykonanie asynchroniczne
Czasem przydaje się zsynchronizowanie wykonania kodu Ninox z JavaScriptem.
Na przykład przy użyciu timera ważne jest, aby kod zakończył się dopiero po zakończeniu działania timera.
Bez takiej synchronizacji kod następujący po wykonaniu JavaScriptu uruchomiłby się natychmiast, co mogłoby prowadzić do nieoczekiwanych zachowań.
W pierwszym przypadku wartość „I don't know” zwracana jest natychmiast, a funkcja alert wyświetla wynik zanim pytanie zostanie w ogóle zadane użytkownikowi.
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 );
Po przejściu w tryb callback (lub async, który jest mu równoważny) funkcja alert Ninox wykonuje się dopiero po wywołaniu przez kod JavaScript funkcji zwrotnej, czyli po zadaniu pytania użytkownikowi. Typ zawsze występuje jako pierwszy: :text:callback, nigdy samo :callback, które zostałoby potraktowane jako typ.
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 );
Wywołanie funkcji
Z poziomu JavaScriptu można wywoływać funkcje Ninox: blok otrzymuje funkcje zadeklarowane wyżej w tej samej formule. Nie widzi funkcji kodu globalnego (zob. niżej, „Wywołanie funkcji kodu globalnego”).
function display( message : text ) do
alert( message );
end;
#{ display('hello world') }#;
Aby odebrać wartość zwracaną przez funkcję, trzeba ponownie użyć trybu callback (patrz wyżej: Wykonanie asynchroniczne):
function add( a : number, b : number ) do
a + b;
end;
#{:number:callback
add( 1, 2, (returnValue) => {
callback( returnValue )
})
}#;
Jeśli po wywołaniu procedury nie mają Państwo nic więcej do przetworzenia, można przekazać funkcję zwrotną bezpośrednio jako parametr:
function add( a : number, b : number ) do
a + b;
end;
#{:number:callback
add( 1, 2, callback )
}#;
Wywołanie funkcji kodu globalnego
Funkcja kodu globalnego nie znajduje się w zasięgu bloku: wywołanie jej po nazwie powoduje w nim błąd. Należy ją wywołać przez ninext.callNinoxFunction, z null jako drugim argumentem. Przy takiej funkcji w kodzie globalnym:
function hello(message : text) do
alert(message)
end;formuła wywołuje ją w ten sposób:
#{ ninext.callNinoxFunction('hello', null, 'hello world') }#;Aby odebrać wartość zwracaną, należy przekazać jako ostatni argument funkcję zwrotną, która otrzymuje ewentualny błąd, a następnie wynik. Gdy powyższa funkcja add znajduje się w kodzie globalnym:
#{:number:callback
ninext.callNinoxFunction('add', null, 1, 2, (error, result) => callback(result))
}#;Wszystko o callNinoxFunction: Funkcje pomocnicze HTML.
Operowanie na rekordach i funkcjach
Jeśli mają Państwo listę identyfikatorów rekordów, mogą Państwo wywołać funkcję Ninox, aby zmodyfikować kolejno każdy rekord. Wystarczy wywołać funkcję i przekazać jej identyfikator.
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;Błędy wykonania
Jeśli w kodzie wystąpi błąd wykonania, zwrócony zostanie tekst komunikatu o błędzie:

W trybie callback ten sam komunikat staje się wynikiem bloku. Powyższy przykład to błąd składni: od wersji 3.2.0 karta Błędy sygnalizuje go przed jakimkolwiek wykonaniem (zob. „Co sprawdza Ninext”).
Przy uruchamianiu: onNinextLoaded
Przy uruchamianiu Ninox wyzwalacz „After Open” wykonuje się zanim Ninext zostanie wczytany: natywny JS nie działa w nim jeszcze, a umieszczony tam blok JavaScript kończy się niepowodzeniem bez żadnego komunikatu.
Jeśli zdefiniują Państwo funkcję onNinextLoaded(event) w wyzwalaczu „After Open”, Ninext wywoła ją, gdy zostanie faktycznie wczytany, u każdego użytkownika, przy każdym otwarciu bazy. event.version podaje wersję Ninext:
function onNinextLoaded(event : any) do
alert("Ninext " + event.version + " is ready");
"… your JavaScript / NativeJS code here";
end;Daje to niezawodny punkt wejścia do uruchamiania JavaScriptu przy starcie albo do dostosowania bazy do wersji Ninext.
Warto wiedzieć
Ninox wykonał już wyzwalacz „After Open” przy otwarciu bazy; aby wywołać onNinextLoaded, Ninext ponownie wykonuje jego kod. Od wersji 3.2.0 ponownie wykonuje tylko jego deklaracje: funkcje oraz — gdy któraś funkcja odczytuje zmienną — zmienne (var, let). Pozostałe instrukcje wykonują się więc tylko raz. Jedynie wartość początkowa zmiennej odczytywanej przez funkcję jest obliczana po raz drugi: nie należy uzależniać jej od zapisu, na przykład od utworzenia rekordu. W rzadkim przypadku, gdy same deklaracje się nie kompilują, Ninext ponownie wykonuje cały wyzwalacz, jak we wcześniejszych wersjach.
Do wersji 3.1.2 włącznie Ninext ponownie wykonuje cały kod wyzwalacza: instrukcje umieszczone poza jakąkolwiek funkcją są wykonywane po raz drugi. Należy to uwzględnić w przypadku tych, które powinny wykonać się tylko raz: utworzenia rekordu, komunikatu, otwarcia tabeli.
