# Usage
Note: CSS variables have been removed since version 2.0.0. From now on, I will only provide a minimal style just to make viable interaction. Expect it to look ugly by default. The main goal of this application is to be able to integrate it seamlessly into your web design. By providing a minimal style, it is easy to add other styles to it to adapt it to your own web design. Have a look at the source code on this page to see how I adapted the style to resemble the default style of the previous version.
Browser
<!DOCTYPE html>
<html dir="ltr">
<head>
<meta charset="utf-8">
<link href="./index.min.css" rel="stylesheet">
<style>
.option-picker {
width: 100%;
}
.option-picker__options {
background: #fff;
}
</style>
</head>
<body>
<p>
<select>
<option>
Option 1
</option>
<option>
Option 2
</option>
<option value="3">
Option 3
</option>
</select>
</p>
<script src="./index.min.js"></script>
<script>
const picker = new OptionPicker(document.querySelector('select'));
</script>
</body>
</html>
Node.js
Functions and methods in this application are mostly native JavaScript and are intended for use by the browser. Node.js doesnโt know about the DOM, so this kind of practice will probably be used more often to build new browser packages than to be used directly in the Node.js server.
CommonJS
const OptionPicker = require('@taufik-nurrohman/option-picker').default;
const picker = new OptionPicker(document.querySelector('select'));
ECMAScript
import OptionPicker from '@taufik-nurrohman/option-picker';
const picker = new OptionPicker(document.querySelector('select'));
# Tests
- No Idea?
- Disabled State
- Grouped Options
- Multiple Instances
- Options from
<datalist>
- Options from Array: 1, 2
- Visible Options
# Tweaks
# Constructor
const picker = new OptionPicker(self, state = {
options: null,
size: null,
strict: false,
with: []
});
# Parameters
self
The <input>
or <select>
element.
state
The configuration data.
state.options
A list of options data as an array, an object, a map, or a function that returns an array, an object, or a map.
Array is the easiest data structure to write, it guarantees that the order will remain the same when transformed into a series of options. With this kind of data structure, where each element is a scalar, the option label will also act as a value after it is transformed into an options list. This is equivalent to creating an <option>
element without a value
attribute.
const options = [
'Option 1',
'Option 2',
'Option 3'
];
const picker = new OptionPicker(document.querySelector('select'), {options});
const options = [
['Option 1', {
value: 1
}],
['Option 2', {
value: 2
}],
['Option 3', {
disabled: true,
value: 3
}]
];
const picker = new OptionPicker(document.querySelector('select'), {options});
Object is another data structure that is also easy to write. The object item keys act as option values, and the object item values act as option labels. The only problem with this data structure is that it cannot guarantee that the order will remain the same when transformed into a series of options, especially if each object key is written as a number.
const options = {
'1': 'Option 1',
'2': 'Option 2',
'3': 'Option 3'
};
const picker = new OptionPicker(document.querySelector('select'), {options});
The solution would be to set the object item key as text and then set the object item value in the attributes object.
const options = {
'option-1': ['Option 1', {
value: 1
}],
'option-2': ['Option 2', {
value: 2
}],
'option-3': ['Option 3', {
disabled: true,
value: 3
}]
};
const picker = new OptionPicker(document.querySelector('select'), {options});
Map is another type of data structure, similar to an object, but it guarantees that the order will remain the same when transformed into a series of options.
const options = new Map;
options.set(1, 'Option 1');
options.set(2, 'Option 2');
options.set(3, 'Option 3');
const picker = new OptionPicker(document.querySelector('select'), {options});
const options = new Map;
options.set(1, ['Option 1', {
value: 1
}]);
options.set(2, ['Option 2', {
value: 2
}]);
options.set(3, ['Option 3', {
disabled: true,
value: 3
}]);
const picker = new OptionPicker(document.querySelector('select'), {options});
Function that returns one of the three data structures above can also be used. The first argument of this function holds the typed search query. Useful for creating dynamic options list capabilities using AJAX.
const options = function (query) {
return [
'Option 1',
'Option 2',
'Option 3'
];
};
const picker = new OptionPicker(document.querySelector('select'), {options});
const options = function (query) {
return fetch('./options.php?query=' + encodeURIComponent(query)).then(response => response.json());
};
const picker = new OptionPicker(document.querySelector('select'), {options});
state.size
Set the value to an integer greater than 1
to display the options list as a scrollable area that is always visible. This layout takes up space and is provided to mimic the behavior of a <select>
element when given the size
attribute. It has a default value of null
. If self
is a <select>
element, then the application will try to use the size
attribute value of that element. This does not apply if self
is an <input>
element, because size
attribute on an <input>
element has different semantics. 1 2
state.strict
Do not allow users to enter a value other than those available in the options list on the โlooseโ option picker presentation. Pressing the Tab key will automatically select the first active option.
state.with
List of callable functions or objects containing an attach()
method to be invoked each time the application is initialized. A very simple โpluginโ system.
# Methods
Instance Methods
Instance methods are methods available through the results of an OptionPicker
construct.
picker.attach(self, state)
Re-initializes the application and its extensions after it has been detached.
picker.attach();
picker.blur()
Blurs from the option pickerโs input or self.
picker.blur();
picker.detach()
Disables the application methods (except for the attach()
method) and executes the detach()
method of the extensions, if they are present.
picker.detach();
picker.fire(event, data, then)
Fires an event.
picker.fire('change', []);
picker.focus(mode = true)
Focuses to the option pickerโs input or self. If it has a text, it will select the text as well.
picker.focus(); // Focus and select the text
picker.focus(-1); // Focus and put the caret to the start of the text
picker.focus(+1); // Focus and put the caret to the end of the text
picker.get(name)
Returns the tag position in the list, starting from 0
.
if (null !== picker.get('foo')) { โฆ }
picker.let(name)
Removes a tag by its name.
picker.let('foo'); // Remove โfooโ tag
picker.let(); // Reset to the initial value
picker.off(event, then)
Removes an event.
picker.off('change'); // Remove all events from the `change` event container
picker.off('change', onChange); // Remove `onChange` event from the `change` event container
picker.on(event, then)
Adds a new event.
picker.on('change', function () {
console.log(this.value.split(this.state.join));
});
function onChange() {
console.log(this.value.split(this.state.join));
}
picker.on('change', onChange);
picker.set(name, at = -1)
Adds a new tag with the given name.
picker.set('foo'); // Append โfooโ tag
picker.set('bar', 0); // Prepend โbarโ tag
picker.set('baz', 2); // Insert โbazโ tag at index 2 in the list
Static Methods
Static methods are methods available directly on the OptionPicker
object.
OptionPicker.from(self, state)
Creates a new OptionPicker
instance.
const picker = OptionPicker.from(document.querySelector('select'));
OptionPicker.of(self)
Gets OptionPicker
instance of an element.
document.querySelectorAll('input[list], select').forEach(self => {
const picker = OptionPicker.of(self);
});
# Properties
Instance Properties
Instance properties are properties available through the results of an OptionPicker
construct.
picker.hooks
Returns the events data.
console.log(picker.hooks);
picker.mask
Returns the option pickerโs mask.
picker.mask.classList.add(picker.state.n + '--dark');
picker.self
Returns the <input>
or <select>
element.
console.log(picker.self.getAttribute('name'));
picker.size
Changes the layout of a drop-down select box to a scrollable area select box. This is valid only if the value is an integer greater than 1
. Otherwise, it will be considered as an invalid value and will revert the layout to its default layout, which is a drop-down select box.
picker.size = 5;
picker.state
Returns the application states if any.
console.log(picker.state);
picker.text
Gets or sets the current text in the option pickerโs input.
console.log(picker.text);
picker.text = 'foo bar baz';
picker.value
Proxy that passes to the picker.self.value
property, with additional actions that are executed while the value is being set.
console.log(picker.value);
picker.on('change', function () {
console.log(this.value);
});
picker.value = 'foo bar baz';
Static Properties
Static properties are properties available directly on the OptionPicker
object.
OptionPicker._
Alias for OptionPicker.prototype
.
OptionPicker._.clear = function () {
if ('input' !== this.self.tagName.toLowerCase()) {
return this;
}
return (this.value = ""), this;
};
const picker = new OptionPicker(document.querySelector('input'));
picker.clear(); // Clear value
OptionPicker.state
Returns the default values of picker.state
.
const picker = new OptionPicker(document.querySelector('select'), {
foo: ['bar', 'baz', 'qux']
});
console.log([OptionPicker.state, picker.state]);
OptionPicker.version
Returns the application version.
# Extensions
Anatomy of an Extension
Extension as a function:
function Extension(self, state = {}) {
this.a = 1;
this.b = function () {};
return this;
}
Object.defineProperty(Extension, 'name', {
value: 'Extension'
});
Extension as an object:
const Extension = {
attach: function (self, state = {}) {},
detach: function (self, state = {}) {},
name: 'Extension'
};
Usage of an Extension
As a core extension:
OptionPicker.state.with.push(Extension);
As an optional extension:
const picker = new OptionPicker(document.querySelector('select'), {
with: [Extension]
});
List of Extensions
# License
Use it for free, pay if you get paid. So, youโve just benefited financially after using this project? Itโs a good idea to share a little financial support with this open source project too. Your support will motivate me to do any further development, as well as to provide voluntary support to overcome problems related to this project.
Thank you! โค๏ธ