Getting started
First control
All controls are created through control factory `new zeta.UI()`.
// create control factory
var ui = new zeta.UI();
// define a button named "demoButton"
var button = ui.button('demoButton');
// render the button in the space on the right
// and context object is returned by render method
var context = button.render(div);
Name vs label
Although label for a control is automatically set to the control's name if not given,
the recommended way to specify labels is either explicitly set on control's options or through `ui.i18n()`.
Examples on this page only use labels directly for brevity.
var ui = new zeta.UI();
var buttonlist = ui.buttonlist(
// directly use label as name
ui.checkbox('Demo Checkbox'),
// recommended way #1
ui.checkbox('demoCheckbox'),
// recommended way #2
ui.checkbox('anotherCbx', { label: 'Demo Checkbox' })
);
// recommended way #1
ui.i18n('en', 'demoCheckbox', 'Demo Checkbox');
// you will see why directly use label as name is not a good idea
// as just changing the label would break you code!
var context = buttonlist.render(div);
console.log(context.toJSON());
// click to inspect =[context]
Icon
Most button-like controls support icons. Currently only Material icons are supported.
For a complete list of icons please see https://material.io/tools/icons.
var ui = new zeta.UI();
var button = ui.button('Done', {
icon: 'done'
});
button.render(div);
Action
Actions can be assigned to any controls by the `execute` option.
Actions are triggered either by user interactions, e.g. mouse click, for button-like controls or
when value is changed for controls that let user to input values to or choose values from.
var ui = new zeta.UI();
var button = ui.button('Click me', {
execute: function () {
console.log('Button clicked');
}
});
button.render(div);
Lifecycle
Init and destroy
var ui = new zeta.UI();
var button = ui.button({
label: 'Click me to remove',
execute: function (self) {
// remove clicked button from button list
self.destroy();
},
init: function (e, self) {
console.log(self.name + ':', 'init');
},
destroy: function (e, self) {
console.log(self.name + ':', 'destroy');
}
})
var buttonlist = ui.buttonlist(
ui.button('Add button', function (self) {
self.parent.append(button);
}),
// append 3 buttons initially
button,
button,
button
);
buttonlist.render(div);
Property change and DOM update
var ui = new zeta.UI();
var buttonset = ui.buttonset(
ui.checkbox({
// templated value will also be re-evaluated and upon changes to other properties
// and is included in propertyChange event if the evaluated string differs from previous value
label: 'Value is {{value}}',
propertyChange: function (e) {
console.log('Old values:', e.oldValues);
console.log('New values:', e.newValues);
},
// stateChange event is fired whenever updates to DOM are needed
// such as changes to control states (enabled, active, ...) or
// property changed, or focus entering or leaving the control
stateChange: function (e) {
console.log('DOM update')
}
})
);
buttonset.render(div);
Async operation
Any control that returns a promise when execution will be automatically locked to prevent double execution.
The `pending` flag of that control will be on during the period, and the `asyncStart` and `asyncEnd` event fired.
var ui = new zeta.UI();
var button = ui.button('Click me', {
execute: function () {
console.log('Do async stuff. Now clicking the button again will not execute again until async end');
return delay(5000);
},
asyncStart: function (e, self) {
console.log('Async operation started. self.pending =', self.pending);
},
asyncEnd: function (e, self) {
console.log('Async operation ended. self.pending =', self.pending);
}
});
button.render(div);
Scripting with control
Finding controls
Controls can be retrieved either through control's `all` property or through the context object.
var ui = new zeta.UI();
var buttonset = ui.buttonset(ui.checkbox(), ui.textbox(), {
init: function (e, self) {
// within control event
// console.log(self.all);
}
});
var context = buttonset.render(div);
// get from context object
// click to inspect =[ui.all(context)]
// alternatively get from DOM element
// click to inspect =[ui.all(div)]
Control state
var ui = new zeta.UI();
var buttonset = ui.buttonlist(
ui.button('Enabled', {
enabled: function () { return true; }
}),
ui.button('Disabled', {
enabled: function () { return false; }
}),
ui.button('Active', {
active: function () { return true; }
}),
ui.button('Hidden', {
visible: function () { return false; }
}),
ui.button('Disabled', {
hiddenWhenDisabled: true,
enabled: function () { return false; }
})
);
buttonset.render(div);
Setting control state
Alternatively the three control states can be set during runtime.
var ui = new zeta.UI();
var buttonset = ui.buttonlist(
ui.button('Enabled', {
init: function (e, self) { self.enabled = true; }
}),
ui.button('Disabled', {
init: function (e, self) { self.enabled = false; }
}),
ui.button('Active', {
init: function (e, self) { self.active = true; }
}),
ui.button('Hidden', {
init: function (e, self) { self.visible = false; }
})
);
buttonset.render(div);
Control dependency
var ui = new zeta.UI();
var buttonset = ui.buttonset(
ui.checkbox('toggle'),
ui.button('demoButton', 'favorite', {
init: function (e, self) {
self.all.toggle.on('stateChange', function (e, checkbox) {
self.enabled = checkbox.value;
});
}
})
);
buttonset.render(div);
Context object
Two-way bindings
By default two-way bindings are created on the context object for controls that has a value.
var ui = new zeta.UI();
var buttonset = ui.buttonset(ui.checkbox(), ui.textbox());
var context = buttonset.render(div);
// try setting values to context object
// or inspect context object after playing controls
context.checkbox = true;
// click to inspect =[context]
// the same object that can retrieve by other components
// click to run =[zeta.dom.getContext(div)]
Action bindings
By default any non-valued control that can be executed, like a button that has the `execute` option defined, method are created on the context object that executes the control.
For other types of control there may also be method created to do other stuff.
See individual control types for more information.
var ui = new zeta.UI();
var button = ui.button('demoButton', function (self) {
console.log('Button clicked');
});
var context = button.render(div);
// click to run =[context.demoButton()]
Custom bindings
Bindings with custom logic can be done via a get/setter.
var ui = new zeta.UI();
var button = ui.button({
init: function (e, self) {
zeta.helper.defineGetterProperty(self.context, 'icon', function () {
return self.icon;
}, function (value) {
self.icon = value;
});
}
});
var context = button.render(div);
context.icon = 'favorite';
Using contextChange event
The contextChange event is an interface where external code can actively notify
about changes that does not simply reflect on simple value change.
var ui = new zeta.UI();
var dropdown = ui.dropdown({
contextChange: function (e, self) {
// event fired when context.update() is called
self.choices = self.context.choices;
}
});
var context = dropdown.render(div);
context.choices = ['One', 'Two', 'Three'];
context.update();
Modularization
Import and export control
var ui = new zeta.UI();
ui.export('custom.namespace',
ui.button('Button 1'),
ui.button('Button 2')
);
var anotherUI = new zeta.UI();
var buttonlist = anotherUI.buttonlist(
anotherUI.import('custom.namespace')
);
buttonlist.render(div);
Labels in separate file
It is common to put language resources in a separate file. Those labels can be imported without accessing control factory by a namespace.
// label.en.js
// add labels to the "example" namespace
zeta.UI.i18n('example', 'en', {
'demoButton': 'Demo Button'
});
// main.js
// use labels in the "example" namespace
var ui = new zeta.UI('example');
ui.button('demoButton').render(div);
Advanced usage
Observing custom property
var ui = new zeta.UI();
var button = ui.button({
init: function (e, self) {
self.watch('customProperty', function (newValue, oldValue) {
console.log('customProperty changed from', oldValue, 'to', newValue);
});
},
propertyChange: function (e) {
// custom property is included in propertyChange event when observed
console.log(e.newValues);
},
execute: function (self) {
self.customProperty = true;
}
});
button.render(div);
Control ordering
var ui = new zeta.UI();
var buttonlist = ui.buttonlist(
ui.button('Last button', { after: '*' }),
ui.button('Button')
);
buttonlist.render(div);
Keyboard and mouse event
var ui = new zeta.UI();
var textbox = ui.textbox({
click: function (e) {
console.log('Mouse clicked');
},
enter: function (e) {
console.log('Key pressed:', e.eventName);
},
keystroke: function (e) {
console.log('Key pressed:', e.data);
}
});
textbox.render(div);
Realm
Controls can be assigned to different realms to identify which contexts those controls required.
It looks for the named property on the toolset state object `self.state` and if the value is a falsy one (e.g. `0`, `false`, `null`, ...), that control will be disabled.
Controls disabled by this way is in the sense that it is truly disabled rather than in a disabled state. No events nor the `enabled` method will be called.
var ui = new zeta.UI('realm', {
contextChange: function (e, self) {
console.log('realm:', self.foo ? 'enabled' : 'disabled');
}
});
var buttonset = ui.buttonset(
// toggle flag and trigger contextChange event
ui.button('Toggle', function (self) {
self.state.foo = !self.state.foo;
self.context.update();
}, { showText: true }),
// only show and enable when foo is true
ui.dropdown('Foo', {
realm: 'foo',
choices: ['One', 'Two', 'Three'],
contextChange: function () {
console.log('dropdown: contextChange event fired');
},
enabled: function () {
console.log('dropdown: enabled method called')
return true;
}
})
);
buttonset.render(div);
Templated label
Templated value can be used for observed properties.
Consult the wiki for waterpipe for template syntax.
var ui = new zeta.UI();
var button = ui.button('Click me', function (self) {
// increment count by each click
self.count = (self.count || 0) + 1;
// display how many clicks in button label
self.label = 'Clicked {{count}} times';
// which is also reflected in control's property
console.log(self.label);
});
button.render(div);
Customizing outlook
var ui = new zeta.UI();
var dropdown = ui.dropdown({
template: '<div><div class="title">{{label}}</div><z:dropdown/></div>',
label: 'Test Dropdown',
choices: ['One', 'Two', 'Three']
});
dropdown.render(div);
Button
Simple button
var ui = new zeta.UI();
var button = ui.button('Click me', function () {
console.log('Button clicked');
});
button.render(div);
Danger button
var ui = new zeta.UI();
var button = ui.button('Danger', {
danger: true
});
button.render(div);
Simulate click
var ui = new zeta.UI();
var button = ui.button('demoButton', function (self) {
console.log('Button clicked');
});
var context = button.render(div);
// execute method is exposed to context object
// same as clicked by user
// click to execute =[context.demoButton()]
Hyperlink button
Link with icon
var ui = new zeta.UI();
var link = ui.link({
icon: 'open_in_new',
label: 'GitHub Homepage',
value: 'https://github.com/misonou/jquery-typer',
target: '_blank'
});
link.render(div);
Menu
Show menu
var ui = new zeta.UI();
var menu = ui.menu(
ui.button('Menu item 1'),
ui.button('Menu item 2'),
ui.button('Menu item 3')
).render(/* notice that no arguments are given here */);
var $link = $('<a href="javascript:void 0;">Show menu</a>');
$link.click(function () {
menu.showMenu(this);
});
$link.appendTo(div);
Context menu
var ui = new zeta.UI();
var menu = ui.menu(
ui.button('Menu item 1'),
ui.button('Menu item 2'),
ui.button('Menu item 3')
).render(/* notice that no arguments are given here */);
zeta.dom.on(div, 'rightClick', function (e) {
menu.showMenu({
x: e.clientX,
y: e.clientY
});
e.preventDefault();
});
div.appendChild(document.createTextNode('Right click in region here'));
Menu button
Simple menu button
var ui = new zeta.UI();
var callout = ui.callout('Menu',
ui.button('Menu item 1'),
ui.button('Menu item 2'),
ui.button('Menu item 3')
);
callout.render(div);
Grouping menu items
var ui = new zeta.UI();
var callout = ui.callout('Menu',
// separator will be displayed for nested button list
ui.buttonlist(
ui.button('Menu item 1'),
ui.button('Menu item 2')
),
ui.button('Menu item 3')
);
callout.render(div);
Toolbar in menu
var ui = new zeta.UI();
var callout = ui.callout('Menu',
// buttonlist required to show the separator
ui.buttonlist(
ui.buttonset(
ui.button('button1', 'favorite'),
ui.button('button1', 'lock')
)
),
ui.button('Menu item 1'),
ui.button('Menu item 2'),
ui.button('Menu item 3')
);
callout.render(div);
Item description
var ui = new zeta.UI();
var callout = ui.callout('Menu',
ui.button('Menu item 1', { description: 'Description 1' }),
ui.button('Menu item 2', { description: 'Description 2' }),
ui.button('Menu item 3', { description: 'Description 3' })
);
callout.render(div);
Command shortcut
var ui = new zeta.UI();
var callout = ui.callout('Menu',
ui.button('Menu item 1', {
// command shortcut is automatically resolved
// when command name is supplied
execute: 'dummy_command'
}),
ui.button('Menu item 2', {
// or manually provide
shortcut: 'ctrlAltQ'
})
);
zeta.dom.setShortcut('dummy_command', 'ctrlAltP');
callout.render(div);
Button mode
var ui = new zeta.UI();
var callout = ui.callout('Menu', 'menu',
ui.button('Disable me', 'favorite', {
init: function (e, self) {
self.enabled = false;
},
execute: function (self) {
// since only one button is enabled after disabling
// callout will become like a normal button
self.enabled = false;
console.log('Enter button mode');
}
}),
ui.button('Button', 'lock_open', {
execute: function (self) {
self.all['Disable me'].enabled = true;
console.log('Enter menu mode');
}
}),
// specifies callout to become button when needed
{ alwaysShowCallout: false }
);
callout.render(div);
Toolbar
Simple toolbar
var ui = new zeta.UI();
var buttonset = ui.buttonset(
ui.button('button1', 'search'),
ui.button('button2', 'favorite'),
ui.button('button3', 'lock')
);
buttonset.render(div);
Hiding button label
var ui = new zeta.UI();
var buttonset = ui.buttonset(
ui.button('button1', 'search'),
ui.button('button2', 'favorite'),
ui.button('button3', 'lock'),
{ showText: false }
);
buttonset.render(div);
Input fields
Dropdown
Simple dropdown
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], function (self) {
console.log(self.value);
});
dropdown.render(div);
Initial value
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], 'One');
dropdown.render(div);
Non-empty
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', ['One', 'Two', 'Three'], {
allowEmpty: false
});
dropdown.render(div);
Using map for choices
// use zeta.shim.Map for support in IE 10
var choices = new zeta.shim.Map();
choices.set(1, 'One');
choices.set(2, 'Two');
choices.set(3, 'Three');
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', choices, function (self) {
// value will be the key added to the map
console.log(self.value);
});
dropdown.render(div);
Fixed label
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', {
valueAsLabel: false,
choices: ['One', 'Two', 'Three']
});
dropdown.render(div);
Additional menu item
var ui = new zeta.UI();
var dropdown = ui.dropdown('Dropdown', {
value: 'One',
choices: ['One', 'Two', 'Three'],
controls: [
// buttonlist required to show line
// between choices and the additional item
ui.buttonlist(
ui.button('Additional button', function () {
console.log('Button clicked');
}),
// show the addition item after choices
{ after: '*' }
)
],
execute: function () {
console.log('Dropdown changed');
}
});
dropdown.render(div);
Checkbox
Simple checkbox
var ui = new zeta.UI();
var checkbox = ui.checkbox('Checkbox', function (self) {
console.log(self.value);
});
checkbox.render(div);
Required
var ui = new zeta.UI();
var checkbox = ui.checkbox('Checkbox', {
required: true
});
checkbox.render(div);
Textbox
Simple textbox
var ui = new zeta.UI();
var textbox = ui.textbox();
textbox.render(div);
Required
var ui = new zeta.UI();
var textbox = ui.textbox({
required: true
});
textbox.render(div);
Multiline textarea
var ui = new zeta.UI();
var textbox = ui.textbox({
options: {
lineBreak: true
}
});
textbox.render(div);
Maximum length
var ui = new zeta.UI();
var textbox = ui.textbox('input', {
options: {
validation: { maxlength: 6 }
}
});
var context = textbox.render(div);
context.input = '012345678';
Character blacklist
var ui = new zeta.UI();
var textbox = ui.textbox('input', {
options: {
validation: { invalidChars: '~"#%&*:<>?/\{|}' }
}
});
var context = textbox.render(div);
context.input = '0123&456?';
Character whitelist
var ui = new zeta.UI();
var textbox = ui.textbox('input', {
options: {
validation: { allowChars: '~"#%&*:<>?/\{|}' }
}
});
var context = textbox.render(div);
context.input = '0123&456?';
Keep label
var ui = new zeta.UI();
var textbox = ui.textbox('input', {
showPlaceholder: 'always'
});
var context = textbox.render(div);
context.input = '0123&456?';
Custom placeholder
var ui = new zeta.UI();
var textbox = ui.textbox('input', {
placeholder: 'This is placeholder. This is a very long description.'
});
var context = textbox.render(div);
Number
Simple number input
var ui = new zeta.UI();
var textbox = ui.number();
textbox.render(div);
Min/max
var ui = new zeta.UI();
var textbox = ui.number({
options: { min: 0, max: 10 }
});
textbox.render(div);
Step
var ui = new zeta.UI();
var textbox = ui.number({
options: { step: 10 }
});
textbox.render(div);
Loop
var ui = new zeta.UI();
var textbox = ui.number({
options: { min: 1, max: 5, loop: true }
});
textbox.render(div);
Tags
Simple tag input
var ui = new zeta.UI();
var textbox = ui.keyword({
execute: function (self) {
console.log(self.value);
}
});
textbox.render(div);
Suggestions
var ui = new zeta.UI();
var textbox = ui.keyword({
options: {
allowedValues: 'ice,tongue,fate,mild,homosexual,dividend,throw,chief,drop,spokesperson,distort,sensitivity,fault,despair,moment,soft,short circuit,bottom,referee,chew'.split(',')
},
execute: function (self) {
console.log(self.value);
}
});
textbox.render(div);
Suggestions label/icon
var ui = new zeta.UI();
var textbox = ui.keyword({
options: {
allowedValues: [
{ value: '1', label: 'One', icon: 'looks_one' },
{ value: '2', label: 'Two', icon: 'looks_two' },
{ value: '3', label: 'Three', icon: 'looks_3' }
]
},
execute: function (self) {
console.log(self.value);
}
});
textbox.render(div);
Defined values only
var ui = new zeta.UI();
var textbox = ui.keyword('tags', {
options: {
allowFreeInput: false,
allowedValues: ['One', 'Two', 'Three']
}
});
var context = textbox.render(div);
context.tags = ['Four'];
Date picker
Date picker
var ui = new zeta.UI();
var datepicker = ui.datepicker();
datepicker.render(div);
Week picker
var ui = new zeta.UI();
var datepicker = ui.datepicker({
options: { mode: 'week' },
execute: function () {
console.log(this.value);
}
});
datepicker.render(div);
Month picker
var ui = new zeta.UI();
var datepicker = ui.datepicker({
options: { mode: 'month' },
execute: function () {
console.log(this.value);
}
});
datepicker.render(div);
Date/time picker
var ui = new zeta.UI();
var datepicker = ui.datepicker({
options: { mode: 'datetime' },
execute: function () {
console.log(this.value);
}
});
datepicker.render(div);
Min/max date
var ui = new zeta.UI();
var datepicker = ui.datepicker({
options: { min: 'today', max: '+14day' },
execute: function () {
console.log(this.value);
}
});
datepicker.render(div);
Calendar
var ui = new zeta.UI();
var calendar = ui.calendar({
execute: function () {
console.log(this.value);
}
});
calendar.render(div);
File upload
Multiple file upload
var ui = new zeta.UI();
var file = ui.file('Upload', 'file_upload', {
multiple: true,
execute: function (self) {
console.log(self.value);
}
});
file.render(div);
Rich text editor
Sample editor
var ui = new zeta.UI();
var rte = ui.richtext();
rte.render(div);
Dialog
Alert box
var ui = new zeta.UI();
var button = ui.button('Click me', function () {
ui.alert('This is an alert box').then(function (value) {
console.log(value);
});
});
button.render(div);
// alternatively you can create alert box without factory
// click to run =[zeta.UI.alert('This is an alert box')]
Confirm box
var ui = new zeta.UI();
var button = ui.button('Click me', function () {
ui.confirm('This is an confirm box').then(function (value) {
console.log(value);
});
});
button.render(div);
// alternatively you can create alert box without factory
// click to run =[zeta.UI.confirm('This is an confirm box')]
Prompt box
var ui = new zeta.UI();
var button = ui.button('Click me', function (self) {
ui.prompt('This is an prompt box', 'Initial value').then(function (value) {
console.log(value);
});
});
button.render(div);
// alternatively you can create alert box without factory
// click to run =[zeta.UI.prompt('This is an prompt box')]
Using label as message
var ui = new zeta.UI();
ui.i18n('en', 'alertMessage', 'This is an alert box');
var button = ui.button('Click me', function () {
ui.alert('alertMessage');
});
button.render(div);
Custom dialog
var ui = new zeta.UI();
var dialog = ui.dialog(
ui.checkbox({
required: true
}),
ui.buttonset(
ui.submit('submit', 'done'),
ui.button('cancel', 'cancel', function (self) {
// close the dialog without executing
return self.all.dialog.destroy();
})
)
);
var button = ui.button('Click me', function () {
// notice that no arguments are given to render()
var context = dialog.render();
context.dialog.then(function (value) {
// do stuff like submitting request to server
console.log('Submitted', value);
}, function () {
console.log('Cancelled')
});
});
button.render(div);
Dialog with async operation
var ui = new zeta.UI();
var dialog = ui.dialog(
ui.textbox(),
ui.checkbox(),
ui.buttonset(
ui.submit('submit', 'done')
), {
execute: function (self) {
return delay(5000);
}
});
var button = ui.button('Click me', function () {
// notice that no arguments are given to render()
var context = dialog.render();
context.dialog.then(function (value) {
console.log('Submitted', value);
}, function () {
console.log('Cancelled')
});
});
button.render(div);
Title and description
var ui = new zeta.UI();
var dialog = ui.dialog(
ui.textbox(),
ui.buttonset(
ui.submit('submit', 'done')
), {
title: 'This is title',
description: 'This is description.'
});
var button = ui.button('Click me', function () {
dialog.render();
});
button.render(div);
Error message
var ui = new zeta.UI();
var dialog = ui.dialog(
ui.textbox(),
ui.buttonset(
ui.submit('submit', 'done')
), {
execute: function (self) {
return zeta.helper.reject('Error occured');
}
});
var button = ui.button('Click me', function () {
dialog.render();
});
button.render(div);
Danger zone
var ui = new zeta.UI();
var dialog = ui.dialog(
ui.checkbox(),
ui.buttonset(
ui.submit('submit', 'done'),
ui.button('delete', 'delete', {
// put this button in danger zone
danger: true,
execute: function (self) {
console.log('Danger button clicked');
return self.all.dialog.destroy();
}
})
)
);
var button = ui.button('Click me', function () {
dialog.render().dialog.then(function (value) {
console.log('Submitted', value);
}, function () {
console.log('Cancelled')
});
});
button.render(div);
Form
Simple form
var ui = new zeta.UI();
var form = ui.form(
ui.textbox('value'),
ui.buttonset(
ui.submit('Submit', 'done')
), {
execute: function () {
// do stuff like submitting request to server
console.log('Send to server', this.context.toJSON());
return delay(5000, { result: 'OK' });
}
});
form.render(div);
Initial values
Although initial values can be supplied as individual `value` option for each control,
it is recommended to supplied it through `render()` method to increase reusability.
var ui = new zeta.UI();
var form = ui.form(
ui.textbox('value'),
ui.buttonset(
ui.submit('Submit', 'done')
)
);
form.render(div, {
value: 'Initial value'
});
Validation
var ui = new zeta.UI();
var form = ui.form(
ui.textbox('value', { required: true }),
ui.buttonset(
ui.submit('Submit', 'done')
),
function () {
// will not execute if textbox is empty
console.log('Form executed');
}
);
form.render(div);
Resetting form fields
var ui = new zeta.UI();
var form = ui.form(
ui.fieldset('Field set',
ui.textbox('Textbox 1'),
ui.textbox('Textbox 2'),
ui.checkbox('Checkbox'),
{ description: 'Try playing with form fields and then click Reset.' }
),
ui.buttonset(
ui.button('Reset', 'undo', function (self) {
self.context.reset();
})
)
);
form.render(div, {
'Textbox 1': 'foo',
'Checkbox': true
});
Form section
var ui = new zeta.UI();
var form = ui.form(
ui.fieldset('Normal section',
ui.textbox('Textbox 1'),
ui.textbox('Textbox 2')
),
ui.fieldset('Optional section',
ui.textbox('value', { required: true }),
{ optional: true, description: 'This is an optional set. When ' }
),
ui.buttonset(
ui.submit('Submit', 'done')
),
function (self) {
console.log('Validation passed')
}
);
var context = form.render(div);
// try playing with the fields and form sections and inspect the values
// click to inspect =[context.toJSON()]