How to create a LuCI form without new form.Map

Hi community,
Is there a way, we can create a LuCI form without "new LuCI.form.Map(config, title, description)" for UCI config files. I am not able to find any example of this. I am using OpenWrt v22.03.5.
Any help would be greatly appreciated


I think, I somehow tried to manage to write a custom form with 3 fields without Luci.form.Map with class as cbi-map. but when I click on the "Save" button, nothing happens i.e. it does not call the save handler of Luci.form.

Looked at form.js below comments for 'Save' button handler

             * Views not using `Map` instances or requiring other special
             * logic should overwrite `handleSave()` with a custom
             * implementation.

Can I get some help or documentation on custom implementation

I have created a form with 2 input fields as below

	render: function() {
	var header = E ('h2', { 'name': 'content' }, _('Example Form'))
	var labl = E ('label' , { 'class' : 'cbi-value-title' }, _('First Option'))
	var labl2 = E ('label' , { 'class' : 'cbi-value-title' }, _('Second Option'))
	var input = E ('input' , { 'id' : 'cbi-first-option', 'type': 'text', 'class' : 'cbi-input-text'})
	var input2 = E ('input' , { 'id' : 'cbi-second-option', 'type': 'text', 'class' : 'cbi-input-text'})
	var val = E ('div', { 'class': 'cbi-value-field' } , input)
	var val4 = E ('div', { 'class': 'cbi-value-field' } , input2)
	var child1 = E ('div', { 'class': 'cbi-value'} , [ labl, val ])
	var child2 = E ('div', { 'class': 'cbi-value'} , [ labl2, val4 ])
	var form = E ('div' , {'id': 'cbi-example', 'class': 'cbi-map'}, 
			[header, child1, child2])			

		return form

Preformatted text
As this form does not use Map or JSONMap, I am not able to understand how to send the form input values to the server side like the rpcd plugin defined as below

var callSetFormData = rpc.declare({
object: 'luci.example',
method: 'setJsonData',
params: [ 'field1', 'field2' ],
expect: { result: false }

Any help in this is greatly appreciated


As you've identified, you would need to override and invoke the rpc object callSetFormData yourself.

See for example how it's implemented in luci-app-firewall.

A quick example I threw together:

'use strict';
'require view';
'require rpc'

var callSystemInfo = rpc.declare({
	object: 'system',
	method: 'info'

return view.extend({
	handleSave: function (ev) {
		return callSystemInfo().then(function(response) {
			console.log('Data from RPC: ' + JSON.stringify(response));