Creating a Custom Field Type in Ninox

Part 3: Communicating from HTML to Ninox

By Adam Davidson, Director of Product Management

This article is the third and final article in a series outlining the steps necessary to create a custom HTML field type in Ninox. If you have not, please go back and read parts one and two before proceeding to read this one.

Last week, communication from Ninox to the HTML input element was established by inserting the ‘Slider Value’ Ninox field into the string being passed to the html() function.  This week, communication in the other direction, from the HTML slider to the ‘Slider Value’ field in Ninox, will be configured.  

Since the HTML cannot directly communicate with Ninox through the browser, we will do this by way of the Ninox API.  The Ninox API allows us to make a request to the server to do anything you might do in the Ninox application.  View all the records in a table, create a new record with specified field values, update the fields of an existing record, delete a record etc.  If you have not already, I recommend reading David’s article on API basics before proceeding.  It will also be useful to take a look at the Ninox REST API documentation.

In order to proceed you will need to get access to one of your Ninox API keys.  In this article the API key will be referenced from a hidden text field in the Formula Code for security.

The end goal is to update the value of the ‘Slider Value’ field via API when the user changes the value of the slider.  This means we will need to use our good old friend from PART 1, events.  

In PART 1 the oninput event was used to update the number above the slider whenever the user changes the value of the slider.  This is great for real-time display, but the oninput event fires every time the slightest movement is made to the slider, and sending out API requests at such a high frequency would cause issues.  All that is needed is to update the value when the user lifts their finger off the mouse when they drop the slider at the desired value.  Thankfully, there is another event, onchange which fires exactly at this time.  Another function can be inserted into the script tag and called from an ‘onchange’ attribute in the input element.

		function updateSliderValue() {
			let sliderVal = document.getElementById('my_slider_val2');
			let slider =
			sliderVal.innerHTML = slider.value;
		async function updateNinox() {
			let slider =;
			slider.disabled = true;
			let currentUrl = location.href;
			let tmId = currentUrl.split('teams/')[1].split('/')[0];
			let dbId = currentUrl.split('database/')[1].split('/')[0];
			let tbId = currentUrl.split('module/')[1].split('/')[0];
			let recId = '" + text(Id) + "';
			let url = '' + tmId + '/databases/' + dbId + '/tables/' + tbId + '/records';
			let data = [{
				id: recId, 
				fields: {
					'Slider Value': slider.value
			const response = await fetch(url, {
    			method: 'POST', 
    			headers: {
      				'Content-Type': 'application/json',
				'Authorization': 'Bearer ' + '" + 'API KEY' + "'
    			body: JSON.stringify(data) 
  			slider.disabled = false;
	<div id='my_slider_val2'>" + text('Slider Value') + "</div>
	<input type='range' min='0' max='100' value='" + text('Slider Value') + "' oninput='updateSliderValue()' onchange='updateNinox()'>

In the HTML above, the updateNinox() function is called from the ‘onchange’ attribute of the slider.  This function has the ‘async’ keyword to enable it to wait for the response from the Ninox server without stopping other processes.

In updateNinox(), we start by disabling the slider while the request is being sent, by setting its disabled attribute to true. The next section gets all of the information needed to locate the current record. Because API requests can be sent from anywhere, they require a complete address to the data that is being updated. For Ninox, we need the team ID, database ID, table ID, and record ID to locate the record we are currently in. This information is available in the url of the current page, and could be hard coded into the HTML, but getting them from the url each time makes the code more transportable to other tables, databases, or teams.
The whole url is accessed with location.href, and stored in the currentUrl variable. This could also be done with the new urlOf(this) ninox function, and inserted into the HTML string. The team ID, database ID, and table id are all extracted from currentUrl by splitting the url with the split() string method. The record Id is inserted from Ninox, since it is a little harder to extract it from the url (it is concatenated to the table ID after ‘/node/’ in the url).
Once the necessary information is extracted from the current url, the url of the API request is constructed using that information, and stored in the ‘url’ variable. Then the data to send to the Ninox API is stored in ‘data’. Take a look at the Ninox REST API Documentation to see how to format the body of the request, and the url of the request.
The actual request is sent out using the fetch() function. There are a couple different ways to send out API calls from javascript in the browser, but fetch is a fairly straightforward way to do so. The fetch function takes two parameters here; the url, and a config object. In the config object, the HTTP method is specified as ‘POST’ (the Ninox API uses the POST method for both creating and updating records). Two headers are specified, the first of which specifies that the body of the request will be in JSON format, and the second of which gives the API key for Authorization. The body of the request consists of the data that we created above. The “JSON.stringify()” function takes a json object and converts it into a string, since this is how the data must be sent via HTTP request.

Once the request is sent, the “await” keyword in front of fetch ensures that the function halts until the response is received from the server before executing the next line of code. Once the fetch() call returns the Ninox server’s response, the slider is re-enabled.
Here is the final slider with two way communication:

There are many customizations you can make to the appearance of the slider which can be found here.