Lookup binding
by whelkaholism
HTML
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.5.1/knockout-latest.js"></script>
<script src="https://cdn.cfront-cloud.co.uk/scripts/koa1.2/cf.linq.js"></script>
<script src="https://cdn.cfront-cloud.co.uk/scripts/koa1.2/cf.DOM.js"></script>
<input type="text" data-bind="lookup: { boundField: Category, source: AvailableCategories, selected: categorySelected, allowDropDown: true }" />
CSS
.koa-lookup {
position: relative;
display: inline-flex;
align-items: center;
gap: 1px;
}
.koa-lookup-items {
display: none;
position: absolute;
background: #ffffff;
z-index: 1;
min-width: 100%;
box-shadow: 5px 5px 15px -3px rgba(0, 0, 0, 0.25);
border-radius: var(--control-radius);
top: 100%;
}
.koa-lookup-items.show {
display: block;
}
.koa-lookup-items > li {
padding: 0.1em 1em;
}
.koa-lookup-items > li:hover,
.koa-lookup-items > li.active {
background: #00000040;
}
.koa-lookup-dropdown:before {
font-family: 'Font Awesome 6 Pro';
content: '\f078';
}
JavaScript
(function()
{
var _getConfig = function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
{
var o = ko.unwrap(f_valueaccessor());
var res = {
obs: o.boundField,
idobs: o.boundIDField,
idField: 'ID',
valueField: 'Name',
source: o.source,
itemTemplate: o.itemTemplate || '{{Name}}',
valueTemplate: o.itemTemplate || '{{Name}}',
rateLimit: typeof (o.rateLimit) != 'undefined' ? o.rateLimit : 300,
renderItem: o.renderItem,
selected: o.selected,
allowDropDown: !!o.allowDropDown,
closeOnBodyClick: o.closeOnBodyClick !== true,
_input: el
};
return res;
};
var _populateTemplate = function(template, item, cfg)
{
var res = (template || '').replace(/\{\{([^\}]+)\}\}/, function(m, g1)
{
var repres = item && ko.unwrap(item[g1]);
return repres || '';
});
return res || '';
};
var _callSource = function(term, cfg)
{
return new Promise(function(resolve)
{
var res = null;
var a = null;
if (ko.isObservableArray(cfg.source))
a = cfg.source();
else if (typeof (cfg.source) == 'function')
cfg.source(term).then(resolve);
else
a = cfg.source;
if (a != null)
{
res = a.where(cfg.predicate || function(x)
{
return new RegExp(RegExp.escape(term), 'i').test(typeof (x) == 'string' ? x : (x && x[cfg.valueField]));
});
}
if (res != null)
resolve(res);
});
};
var _renderItem = function(item, cfg)
{
if (cfg.renderItem)
return cfg.renderItem(item, cfg);
...