原生 JS
原生 JS 讓您可以在 Ninox 腳本中執行 JavaScript 程式碼,並與腳本共用函式與變數。如此一來,原生 JS 就能讀取 Ninox 變數,並呼叫同一個公式中宣告的函式;至於全域程式碼中的函式,則要透過 ninext.callNinoxFunction 呼叫(參見下文「呼叫全域程式碼中的函式」)。
原生 JS 預設為啟用;它可以在 Ninext 設定的「JavaScript 整合」區段中停用(原生 JavaScript)。

限制
在原生 JS 中修改 Ninox 變數,並不會影響該 Ninox 變數。
JavaScript 只會在本機執行。把 JavaScript 加進在伺服器上執行的程式碼中不會有任何效果;同樣地,從在伺服器上執行的程式碼呼叫含有 JavaScript 的全域函式,也不會有任何效果。自 3.2.0 版起,錯誤分頁會標示直接放在表格觸發器(建立後、修改後)或 do as server 中的區塊。
哪些程式碼在本機執行、哪些在伺服器上執行,請參見下圖:

語法
執行
若要告訴 Ninox 您正切換到 JavaScript,必須把程式碼包在 #{ ... }# 之中:
#{ alert("hello world") }#;別忘了,Ninox 是預先編譯的語言,必須事先知道每個變數與函式的型別。原生 JS 也是如此:您必須指定 JavaScript 程式碼所回傳的型別。原生 JS 預設回傳 text,但您可以在程式碼最開頭以 :[type] 這種寫法指出想回傳的變數型別。
註解要緊貼著 #{,不能有任何空格:#{:number …,而不是 #{ :number …。同樣地,兩個註解要緊接著寫,中間不留空格(:text:callback)。若有空格,註解就不會被辨識:區塊會被當作文字型別,而註解會留在 JavaScript 程式碼中,造成語法錯誤。
回傳值
#{:text return "hello world"}#;可用的型別有:text、number、date、timestamp(日期與時間)、time、timeinterval、appointment、boolean、html、color、icon、email、phone、location、file、user、json 以及 any。完整的清單(包括 choice、link、style 與 styled)會由控制台提示(見下文)。
注意
帶時間的日期要註記為 :timestamp,而同一型別的函式參數則宣告為 datetime。註解中並沒有 :datetime:區塊會被當作文字型別。自 3.2.0 版起,錯誤分頁會標示未知的註解。
日期、時間與時長都以毫秒交換:這類型別的 Ninox 變數會以數字形式進入 JavaScript,而 :date 或 :array(date) 區塊必須回傳毫秒(也就是 JavaScript 日期的 getTime() 所提供的值)。
陣列型別
若要回傳值的陣列,請以 :array(type) 指定其元素的型別(自 3.2.0 版起):
#{:array(number) return [1, 2, 3] }#;所有簡單型別皆可使用::array(text)、:array(date)、:array(any)…
在 3.1.2 版(含)之前,只能回傳型別為 any 的陣列。這種寫法仍然有效,等同於 :array(any):
#{:any(array) return [1, 2, 3] }#;本頁過去所介紹的 :number(array) 寫法並不會回傳陣列。自 3.2.0 版起,錯誤分頁會將這種寫法標示出來。
記錄型別
若要回傳記錄,請使用 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] }#採用這種語法時,原生 JS 回傳的變數,其行為與 Ninox 程式碼中的變數完全相同。也就是說,您可以像使用 select 一樣寫出下列語法:
(#{:rid(customer) return [1,2,3] }# order by 'Last Name').'First Name';
控制台中的輸入輔助
自 3.2.0 版起,控制台會協助您撰寫區塊:
- 在註解中:在
#{之後緊接著輸入:時,它會提示回傳型別、array(type)、nid(Table)與rid(Table);在nid或rid之後輸入(時,會列出表格,在array之後則列出型別;第二個:會提示修飾詞callback與async; - 在 JavaScript 中:自動完成會以 JavaScript 形式,提示區塊所收到的 Ninox 變數與函式,接著在句點之後,提示物件的成員——若是記錄,則是其欄位名稱(參見控制台頁面中的「原生區塊中的 JavaScript 自動完成」)。
這項輔助只存在於控制台中。
Ninext 會檢查什麼
自 3.2.0 版(測試版)起。 錯誤分頁會檢查整個資料庫中的
#{ … }#區塊,控制台則檢查您在其中撰寫之程式碼裡的區塊。
會被標示的有:
- JavaScript 語法錯誤;
- 未知的註解(例如
:datetime),或在:nid(…)或:rid(…)中找不到的表格:區塊會被當作文字型別; - 有型別卻完全沒有
return的區塊,或部分路徑一個也無法到達的區塊:它會回傳空值; - 從未呼叫
callback的:callback或:async區塊:公式將永遠得不到值; - 直接放在表格觸發器(建立後、修改後)或
do as server中的區塊,它在那裡不會執行。
修改記錄
記錄型別的變數以 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"
}此外,物件還帶有一個 _node 鍵:也就是 Ninox 所儲存的記錄,其欄位以內部識別碼表示。
重要
視程式碼是在 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 );
改用 callback 模式(或與之等效的 async)之後,Ninox 的 alert 函式只會在 JavaScript 程式碼呼叫回呼函式之後才執行,也就是在問題已經呈現給使用者之後。型別一律放在最前面::text:callback,絕不能只寫 :callback,否則它會被當成型別。
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 );
呼叫函式
您可以從 JavaScript 呼叫 Ninox 函式:區塊會收到同一個公式中較早宣告的函式。它看不到全域程式碼中的函式(參見下文「呼叫全域程式碼中的函式」)。
function display( message : text ) do
alert( message );
end;
#{ display('hello world') }#;
若要取得函式的回傳值,同樣必須使用回呼模式(參見上文:非同步執行):
function add( a : number, b : number ) do
a + b;
end;
#{:number:callback
add( 1, 2, (returnValue) => {
callback( returnValue )
})
}#;
如果呼叫該程序之後沒有其他要處理的事,您也可以直接把回呼函式當作參數傳入:
function add( a : number, b : number ) do
a + b;
end;
#{:number:callback
add( 1, 2, callback )
}#;
呼叫全域程式碼中的函式
全域程式碼中的函式不在區塊的作用範圍內:在區塊中以名稱呼叫它會造成錯誤。請改以 ninext.callNinoxFunction 呼叫它,並以 null 作為第二個引數。若全域程式碼中有這個函式:
function hello(message : text) do
alert(message)
end;公式便這樣呼叫它:
#{ ninext.callNinoxFunction('hello', null, 'hello world') }#;若要取得回傳值,請在最後一個引數傳入回呼函式,它會依序收到可能的錯誤與結果。以放在全域程式碼中的上述 add 函式為例:
#{:number:callback
ninext.callNinoxFunction('add', null, 1, 2, (error, result) => callback(result))
}#;關於 callNinoxFunction 的一切:HTML 輔助函式。
操作記錄與函式
如果您有一份記錄 ID 的清單,可以呼叫 Ninox 函式逐一修改每筆記錄。做法很簡單:呼叫該函式並把 ID 傳進去即可。
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;執行錯誤
如果您的程式碼發生執行錯誤,就會回傳錯誤訊息的文字:

在 callback 模式下,同樣的訊息會成為區塊的結果。上面的範例是語法錯誤:自 3.2.0 版起,錯誤分頁會在任何執行之前就將它標示出來(參見「Ninext 會檢查什麼」)。
啟動時:onNinextLoaded
Ninox 啟動時,「After Open」觸發器會在 Ninext 載入之前執行:此時原生 JS 尚無法運作,放在那裡的 JavaScript 區塊會悄悄地失敗。
若您在「After Open」觸發器中定義 onNinextLoaded(event) 函式,Ninext 會在真正載入完成後呼叫它——對每位使用者、在每次開啟資料庫時皆然。event.version 提供 Ninext 的版本:
function onNinextLoaded(event : any) do
alert("Ninext " + event.version + " is ready");
"… your JavaScript / NativeJS code here";
end;如此一來,您便有一個可靠的進入點,可在啟動時執行 JavaScript,或讓您的資料庫配合 Ninext 的版本加以調整。
須知
開啟資料庫時,Ninox 已經執行過「After Open」觸發器;為了呼叫 onNinextLoaded,Ninext 會重新求值其程式碼。自 3.2.0 版起,它只重新求值其中的宣告:各個函式;若有函式讀取了其中的變數(var、let),也包括這些變數。因此,其他指令只會執行一次。只有被函式讀取的變數,其初始值會被再次計算:請勿讓它依賴於寫入操作,例如建立記錄。在少數情況下,若這些宣告單獨無法編譯,Ninext 會像先前的版本一樣,重新求值整個觸發器。
在 3.1.2 版(含)之前,Ninext 會重新求值觸發器中的所有程式碼:放在任何函式之外的指令會被執行第二次。對於只應執行一次的指令,請將這點納入考量:建立記錄、顯示訊息、開啟表格。
