-
Notifications
You must be signed in to change notification settings - Fork 4
DynamicList
DynamicList is an object to manipulate and display a list of objects (Views, Templates, or more OML trees). It extends List and most its methods are a mirror of
OGX.List
.
Extends
Uxi, Touch
Requires
Templater, List
{"selector:DynamicList":{CONFIG}}
DynamicList can also be created on the fly, at runtime
let config = {
el:_SELECTOR_, //mandatory
display:_OBJECT_, //mandatory, the display object to use, see Display Object
display_max:_INT_, //optional, max items to display
mode:'single|multi|toggle|hit|static|set', //optional, defaults to 'single',
reselect:_BOOLEAN_, //Optional, only applicable to 'mode:single', triggers select again even if item is already selected
reorder:_BOOLEAN_, //Optional, if the user can tap-hold-drag an item to change its position, defaults to false
swipe:_BOOLEAN_, //Optional, if list items are swipe-able, see swipe subsection, defaults to false
trigger:true|false, //optional, triggers on rendering, defaults to false
key:'_UNIQUE_OBJ_KEY_' //optional but recommended, a property available across the entire data list, such as "id"
as:_STRING_, //optional, a keyword for scope targeting in oml rendering, defaults to 'item',
scope:_BOOLEAN_, //optional, if the list is sensitive to scope, defaults to true
list:_ARRAY_, //optional, the data as array as objects,
selection:_ARRAY //optional, an array of values from the key, of each element to select. Requires setting key.
no_selection:_OBECT_ //optional, an object to define what items cannot be selected,
callbacks: _OBECT_ //optional, see callbacks
};
As an OML node
let node = {};
node["#myDiv:DynamicList"] = config;
OGX.OML.render(this, OML);
From a Uxi node
let list = this.create('DynamicList', config);
Independently
let list = OGX.Object.create('DynamicList', config);
The
mode
option defines the selection mode.'single'
stands for only one item selected at a time,'multi'
for multiple selection and'toggle'
to only have one item at a time that you can unselect as well.hit
triggers the event and returns data but never selects the item in the list.set
acts like a push button where selected items cannot be unselected.
There are multiple display modes. If all the items of the list inherit the same template, or HTML markup, you set it up like this
"display" : {
"template" : "Mytemplate",
//template OR html
"html" : "<span>{{$name}}</span>"
"css" : "my_css"
}
However, if you wish to render a non uniform list of objects using multiple templates or markups, you need to bind it to a property and set the display per value of the property. The following is taken from the demo app where the
display
is bound to a propertytype
of each item. Each type has a differentdisplay
and some even useOML
"display":{"bind":"type"},
"displays":{
"ad":{"template":"Ad", "css":"ab"},
"post":{"template":"Post", "css":"user user_post"},
"galery":{
"oml":{
"default:Carousel":{
"dots":true
}
},
"placeholder":{
"images":{"default:Html":{"html":"<span class=\"galery_img\" style=\"background-image:url({{$images}});\"></span>"}}
}
}
}
You should provide a
key
every time your objects have a unique value (such as an id). If no unique key is not provided, the list auto assigns a unique id that is removed if you retrieve the list. For instance, if your list of objects is a list of users with unique propertyid
, you should set your list this way
key:'id'
If you do provide a
key
, you can skip theproperty
argument for methodsfind
,findDelete
,update
,replace
,restore
.
list.findDelete('id', 10, 1); //key is not set, expects combo property/val
list.findDelete(10, 1); //key is set, no need to pass a property here unless not targetting 'id'
You can also set the key on the fly
list.key('id');
For the rest of the documentation, please consider the following super array (simple array acceptable too)
let array = new OGX.List(
{id:1, name:'Chad', age:20, gender:'male', registered:'2017-01-01'},
{id:2, name:'Sarah', age:30, gender:'female', registered:'2017-01-02'},
{id:3, name:'Tyrone', age:25, gender:'male', registered:'2017-01-03'},
{id:4, name:'Stacy', age:40, gender:'female', registered:'2017-01-04'}
);
list.val(_ARRAY_);
let array = list.val();
list.enable();
list.disable();
OGX.DynamicList uses Templater to templatize the items of the list via a Display. It is recommended you check it out both components in depth if you haven't done so yet. But this component brings a few advantages over a simple list, such as multiple templates.
list.order(_PROPERTY_, _WAY_);
To sort a list of objects on their common property first_name ascending do
list.order('fist_name', 1);
To sort a list of objects on their common property age descending do
list.order('age', -1);
list.insert(_OBJECT_|_ARRAY_, _INDEX_); //If index is not specified, the object will be added at the end of the list
list.delete(_INDEX_); //This is the display index here, must be displayed
list.deleteSelection(); //Delete the selected items
list.findDelete(_PROPERTY_, _VALUE_, _LIMIT_); //Find and delete items, returns array of deleted items
list.findReplace(_PROPERTY_, _VALUE_, _NEW_OBJECT_); //Finds and replace first match, returns true|false
list.findUpdate(_PROPERTY_, _VALUE_, _NEW_OBJECT_, _STRICT_, _LIMIT_); //Finds and updates first match with a partial or complete object, returns number of updated items
list.findIndex(_PROPERTY_, _VALUE_) //Find the index of the first object containing the property/value combination
list.replaceAt(_INDEX_, _OBJ_) //Replace an object given index
list.refreshAt(_INDEX_) //Renders item at index
list.getElement(_PROPERTY_, _VALUE_); //Return HTML element of first found property/value combo
list.key(*); //Sets the key (use before passing a list)
list.select(_PROPERTY_, _VALUE_, _OPTIONAL_TRIGGER_); //Adds items to selection array and return it (or object if single mode)
list.unselect(_PROPERTY_, _VALUE_); //Remove from select
list.selectIndex(_INDEX_, _OPTIONAL_TRIGGER_); //In the displayed list only
list.unselectIndex(_INDEX_); //In the displayed list only
list.getSelection(_BOOLEAN_); //Get selected objects. If set to true, get selected elements instead. Default false.
list.resetSelection();
list.index(_INDEX_) //Retrieve or select index, if no index passed, it returns selectedIndex
list.noSelection(*) //Sets, enable or disable the no selection option
Matches a property/value pair to select item(s), to select a user based on his id equal to 100, do
list.select('id', 100);
Get selected item(s)
list.getSelection(); //Return an OGX.list
Get selected element(s)
list.getSelection(true); //Return an array of elements
Reset the selection of this list (unselect all)
list.resetSelection();
Select also support selecting multi items at once
1.14.0+
list.select('_id', ['100', '101']);
You can also select at start of the list by setting the selection array, such as
{..., "selection" : ['20', '22', '35']}
Note that a
key
must be set and that the values of the selection array are the values of eachitem.key
You can prevent some items of the list from being selected, by setting the
no_selection
flag in the config, such as
"no_selection" : {enabled:_BOOL_, prop: OBJECT_PROPERTY, val:OBJECT_PROPERTY_VALUE};
For instance, if your items have a property named "selectable" with a value of 0 to prevent selection, and 1 to allow selection, you would write
"no_selection" : {enabled:true, prop: "selectable", val:1};
You can turn it on/off any time by doing
list.noSelection(true);
list.noSelection(false);
And update the property/value pair
list.noSelection('can_select_me', 1);
You can also set the entire object at once
list.noSelection({enabled:true, prop:'color', val:'red'});
list.render(); //Renders the whole list
list.wipe(); //Clears the display
To update a selected object in the list from a partial object and without rendering the entire list, do
list.findUpdate('id', 1, {name:'Chaddy'});
This is useful for instance, if the end user edits the value, via a form or another view, of a property of a selected object, and that change should be reflected in the display.
DynamicList can be filtered using the same filters as List. it provides shortcut methods to the internal list.
list.addFilter(__property, __mode, __value);
list.removeFilter(__property, __mode, __value);
list.resetFilters();
list.getFilters();
list.filter();
list.unfilter();
DynamicList can be bound to other elements that can control the filtering of the list. It is possible to bind a common property of the objects of a list, to another HTML element or OGX.JS component.
list.bind(_OBJECT_);
list.unbind(_PROPERTY_);
The expected object must match the following format
{property:_STRING_, object:*, mode:_STRING_}
In this example, we filter our list by matching the common property first_name via an input[type=text]. Every time the user inputs in this field, the list is going to be filtered and rendered
list.bind({property:'first_name', object:'#my_input', mode:'in'});
If we wanted to only filter once the user has typed at least 3 characters, we can use the min_length property, such as
list.bind({property:'first_name', object:'#my_input', mode:'in', min_length:3});
In this example, we filter our list by matching the common property price via an input[type=range] using the option 'lt' (lesser than) as a price limit
list.bind({property:'price', object:'#my_input', mode:'lt'});
DynamicList can be bound to another instance of DynamicList. The second list doesn't have to have the same properties. For instance, if you bind a DynamicList to another DynamicList, you can specify a remote_property property which is the property used in the 2nd list to filter out the first list.
list_1.bind({property:'sex', object:list_2, remote_property:'gender', mode:'eq'});
By default, OGX.JS will try to convert the value of an element to its proper type. For instance, if the value of a field is a string "50", then it will be automatically converted to a number instead. You can turn this off by setting
convert: false
in the bind options.
If you bind a component that returns an object with multiple properties, such as a RouletteTree, you have two options.
- If the objects of your list have the properties inside an object, such as
{location:{country:"CA", state:"ON"}}
then you can directly bind the RouletteTree with it
list.bind({property:'location', object:my_roulette_tree, mode:'in'});
- If the objects of your list have the properties at object root, such as {country:"CA", state:"ON"} then you have to remap the properties, such as
list.bind({property:['country', 'state'], object:my_roulette_tree, mode:'in'});
- If the objects of your list have the properties at object root but are different than the ones used in the component, remap them as well
list.bind({property:['country', 'state'], remote_property:['country', 'province'], object:my_roulette_tree, mode:'in'});
MODE is the comparison mode or the filtering mode. To check out the supported modes, please refer to List under Filtering modes.
You can also use OML to setup your binds, here an input field filters by
user.first_name
"user.first_name:Bind": {
"object": "#my_filters input[name=\"first_name\"]",
"mode": "in"
}
Binding other components with OML, here a
Tag
componentmy_tags
filters byuser.tags
"user.tags:Bind" : {
"object:OSE": "{{uxi my_tags:Tags}}",
"mode": "in"
}
DynamicList supports reordering. If you set the reorder flag to true, the end user will have the possibility to tap and hold an item of the list, to make it float, then drag and drop the item at a new position.
{...,
reorder:true,
hold_time:2000 //Optional
}
By default, the hold_time (touching/pressing down time to be elapsed before the item becomes drag-able) is set at 2000ms but you can adjust it as you want.
This component also supports swipe. You can set the swipe flag to true to allow the end user to swipe-to-delete an item of the list.
{...,
swipe:true
}
There are two swipe modes supported so far: OGX.DynamicList.SWIPE_MODE_DELETE and OGX.DynamicList.SWIPE_MODE_SIDE.
The default mode is SWIPE_MODE_DELETE. Use this mode if the only result of the swipe action is to delete from the list.
The SWIPE_MODE_SIDE mode will reveal two different backgrounds depending on the side of the swipe. These backgrounds are editable via CSS.
By default, the configuration that will be used when you turn swipe on is:
{
mode:OGX.DynamicList.SWIPE_MODE_DELETE,
template:false,
html:''
}
You can overwrite that configuration by passing an object to swipe instead. In this case, the content of the background item is stored in OGX.Templater
{...,
swipe:{
mode:OGX.DynamicList.SWIPE_MODE_DELETE,
template:_NAME_OF_YOUR_TEMPLATE_
}
}
You can use a custom HTML instead of using the templater
{...,
swipe:{
mode:OGX.DynamicList.SWIPE_MODE_DELETE,
html:'<span>This item was deleted</span>'
}
}
For the SWIPE_MODE_SIDE mode, once an item has been sided, the component will trigger OGX.DynamicList.SIDED and will pass along an object containing the side and the item. You can restore a sided item by calling restore and passing a combo property/value to find the item in the list.
list.restore(__prop, __val);
If your list is
scroll
, then you can use thescroll
method to scroll to an item of the list
list.scroll('id', 'a12345678bgf153');
OGX.DynamicList.SELECT
OGX.DynamicList.UNSELECT
OGX.DynamicList.DELETE
OGX.DynamicList.SWIPE_LEFT
OGX.DynamicList.SWIPE_RIGHT
OGX.DynamicList.BACK_HIT //Triggered when an item has been SIDED and user tap the background
OGX.DynamicList.SIDED //Triggered when an item has been set aside in SWIPE_MODE_SIDE
OGX.DynamicList.HOLD //Triggered when the end user inits a drag after tap holding an item for 2 sec
OGX.DynamicList.DROP //Triggered when the end user ends a drag/reorders the list
OGX.DynamicList.RENDER //Triggered when the list has rendered. Can also be used to track filtering actions
OGX.DynamicList.READY //Triggered once when the component is ready
OGX.DynamicList.SELECT_FILTERED //Triggered when the selection has changed due to filtering/binding
OGX.DynamicList.SELECT_UNFILTERED //Triggered when the selection has resetted due to filtering/binding
If you'd rather have a callback instead of dealing with events (for some events), you can set callbacks in your config, or on the fly. Supported callbacks are
select
,unselect
andrender
Setting callbacks at config
{..., callbacks:{select: mySelectFunction, unselect: myUnselectFunction, render: myRenderFunction}}
Note that you can also setup callbacks with OML and OSE using the
method
Node
Setting callbacks at runtime
list.onSelect = mySelectFunction;
list.onUnselect = myUnselectFunction;
list.onRender = myRenderFunction;
list.reset();
list.destroy();
In this example, we are creating at runtime and displaying the name and the gender of every element of our list, using straight up HTML as template and the 'user' css class to style the template, inside a '#list' HTML element of a page. Then we listen for user interactions over an item of the list.
let dlist = this.create('DynamicList', {
el:'#list',
key:'id',
display:{html:'<span class="name">{{$name}}</span><span class="gender">{{$gender}}</span>', css:'user'},
list:array
});
dlist.el.on(OGX.DynamicList.SELECT, function(__event, __data){
//__data is the complete item of the list that was clicked
});
Same result but using a route and OML in
app.json
and storing users in a json document
...,
"stage/myroute": {
"default #list:Views.MyView": {
"id": "list",
"template": "MyTemplate",
"node:OML":{
"#myselector:DynamicList":{
"key":"id",
"display":{
"html":"<span class="name">{{$name}}</span><span class="gender">{{$gender}}</span>",
"css":"user"
},
"list:OSE":"{{json users}}"
}
}
}
}
You don't have to store and pass data to the list if you are fetching the data from a remote call.
"list:OSE":"{{json users}}"
is optional. You can then get the instance of the DynamicList from your view by doing
var list = app.cfind('DynamicList', 'list');
Or by looking up in the view's OML nodes
var list = this.find('DynamicList', 'list');
and then you can pass it your data
list.val(my_array);
In this example, we render a list of subscriptions, with a Switch in each and every one of them. the id of every object (templates and switches) is generated based on the item's id of the list. The important property is
as
which defines the mirror of the object off of the list, and then can be used in theOML
tree usingOSE
scripting.
"#subscriptions > .list:DynamicList":{
"id":"subscriptions",
"mode":"static",
"as":"sub",
"display":{
"oml":{
"default:Templates.Subscription":{
"css" : "subscription",
"id:OSE":"#{{&sub._id}}",
"data:OSE": "{{&sub}}",
"node:OML":{
"#{{&sub._id}} .switch:Switch":{
"id:OSE":"#{{&sub._id}}_switch"
}
}
}
}
}
}
- Welcome
- Changelog
- Structure
- Configuration
- Getting started
- CLI
- Poly
- Core
- Templating
- Routing
- Controllers
- Components
- Extra Components
- Helpers
- Styling
- Debugging