Native JS

Native JS позволяет выполнять код JavaScript внутри скрипта Ninox и обмениваться с ним функциями и переменными. Благодаря этому Native JS может обращаться к переменным Ninox и вызывать как локальные, так и глобальные функции.

image.png

Ограничения

Изменение переменной Ninox в NativeJS не затрагивает саму переменную Ninox.

JavaScript выполняется только локально. Добавление JavaScript в код, выполняемый на сервере, не даёт никакого эффекта. Точно так же не даёт эффекта вызов глобальной функции с JavaScript из кода, выполняемого на сервере.

Здесь показано, какие коды выполняются локально, а какие на сервере:

image.png

Синтаксис

Выполнение

Чтобы указать Ninox, что вы переходите на JavaScript, заключите код в #{ ... }#:

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

Помните: Ninox — предварительно компилируемый язык, которому нужно заранее знать тип каждой переменной и функции. То же относится и к Native JS: вы должны указать тип, возвращаемый кодом JavaScript. По умолчанию Native JS возвращает текст, но нужный тип можно задать в самом начале кода записью :[type]:

Возвращаемое значение

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

Возможны те же типы, что и при объявлении функций: text, number, date, datetime, time, timeinterval, appointment, boolean, html, color, icon, email, phone, location, file, user и any.

Типы массивов

Чтобы вернуть массив, используйте такой синтаксис:

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

Типы записей

Чтобы вернуть записи, укажите имя таблицы, а за ним nid или rid:

Если вы используете nid, нужно вернуть массив текстовых значений с полным идентификатором записи, то есть идентификатором таблицы + номером записи:

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

Если вы используете rid, следует вернуть номер записи:

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

Для составных имён таблиц не добавляйте , как в Ninox, а просто пишите полное имя таблицы:

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

При таком синтаксисе Native JS возвращает переменные, которые ведут себя так же, как в коде Ninox. Значит, можно писать так, будто это select:

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

image.png

Изменение записи

Переменные типа «запись» передаются в формате JSON, где каждому полю записи соответствует пара ключ-значение.

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

Здесь содержимое переменной r в JavaScript выглядит так:

{
 "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"
}

Важно

В зависимости от того, выполняется ли код в приложении для Mac или в вебе, регистр ID может отличаться.
Чтобы учесть это и избежать расхождений между платформами, ID повторяется во всех возможных вариантах написания.

Изменение записи в JavaScript не обновляет её в Ninox.

Асинхронное выполнение

Иногда бывает нужно согласовать выполнение кода Ninox с JavaScript.
Например, при работе с таймером важно, чтобы код завершался только после того, как таймер отработает.
Без такого согласования код, следующий за выполнением JavaScript, отработает сразу же, что может привести к неожиданному поведению.

В первом случае значение «I don’t know» возвращается немедленно, и функция alert показывает результат раньше, чем вопрос будет задан пользователю.

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

Если перейти в режим callback, функция alert в Ninox выполнится только после того, как код JavaScript вызовет функцию обратного вызова, то есть после того, как вопрос будет задан пользователю.

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 );

Запись экрана 2025-03-03 в 11.46.26.gif

Вызов функции

Из JavaScript можно вызывать функции Ninox. Процедура может быть локальной или глобальной — важно лишь, чтобы она находилась в области видимости кода JavaScript.

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

image.png

Чтобы получить возвращаемое значение функции, снова понадобится режим callback (см. выше: Асинхронное выполнение):

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

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

image.png

Если после вызова процедуры никакой дальнейшей обработки не требуется, функцию обратного вызова можно передать параметром напрямую:

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

image.png

Работа с записями и функциями

Если у вас есть список идентификаторов записей, можно вызвать функцию Ninox, чтобы изменить каждую запись по очереди. Для этого достаточно вызвать функцию и передать ей идентификатор.

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;

Ошибки выполнения

Если в коде происходит ошибка выполнения, возвращается текст сообщения об ошибке:

image.png