Skip to content

Instantly share code, notes, and snippets.

@matt212
Last active May 15, 2018 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save matt212/0418912d8f4c1b7d1630434fa27f9974 to your computer and use it in GitHub Desktop.
Save matt212/0418912d8f4c1b7d1630434fa27f9974 to your computer and use it in GitHub Desktop.
Custom Modular Multiselect plugin and its implementation
<!--
reason for creating this plugin
https://select2.org/programmatic-control/add-select-clear-items#preselecting-options-in-an-remotely-sourced-ajax-select2
which states that We need to modify our server api for client side plugin feature which is reallllly BAD !
also if you guys find any multiselect + autopopulate with ajax and edit mechanism please comment below on gist !
1. include modular-multiselect-plugin.js in base.html
2. include data-utils.js & plugin-enduser-implementation.js in base.html
3. include modular-multiselector.css in base.html
plugin in action Jsfiddle
https://jsfiddle.net/bilbobaggins/o8zLoora/
for eval purpose ajax part of autopopulate search is from static object array which devs need to place promise based $ajax
in any way possible GET,POST with or without custom accesstokens sky is the limit
-->
<div id="inpfirst_name">
</div>
String.prototype.capitalize = function() {
return this.replace(/(^|\s)([a-z])/g, function(m, p1, p2) {
return p1 + p2.toUpperCase();
});
};
Array.prototype.remByVal = function(val) {
for (var i = 0; i < this.length; i++) {
if (this[i] === val) {
this.splice(i, 1);
i--;
}
}
return this;
}
let datatransformutils = {
findAndRemove: function(array, property, value) {
array.forEach(function(result, index) {
if (result[property] === value) {
//Remove from array
array.splice(index, 1);
}
});
},
rename: function(obj, oldName, newName) {
if (!obj.hasOwnProperty(oldName)) {
return false;
}
obj[newName] = obj[oldName];
delete obj[oldName];
return true;
},
removeJsonAttrs: function(json, attrs) {
return JSON.parse(JSON.stringify(json, function(k, v) {
return attrs.indexOf(k) !== -1 ? undefined : v;
}));
},
isNumberKey: function(evt) {
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode != 46 && charCode > 31 && (charCode < 48 || charCode > 57))
return false;
return true;
}
}
var multisel = function basemultiselect(selconfig, callback) {
let me = {};
me.identifier = selconfig.selectevent;
me.callbackfunc = callback
me.remotefunc = selconfig.remotefunc;
me.internset = [];
me.internbasearh = [];
me.fieldname = selconfig.fieldkey;
me.fieldval = "";
me.filterparam = {};
me.internbasesearchar = [];
me.base = {};
me.basesearchar = []
me.init = function() {
this.$el = $('' + this.identifier + '');
this.$el.addClass('spanmul')
this.renderinputtag();
this.$input = this.$el.find('input');
this.appendautopopulate(this.$input);
this.bindEvents()
//do other important setup things
},
me.bindEvents = function() {
this.clickscrolleventstoggle();
this.$input.on('input', this.addPerson.bind(this));
this.$el.off();
this.$el.on('keypress', this.dvkeyscroll.bind(this))
this.$el.on('keyup', this.dvkeyscrollup.bind(this))
this.$ul = this.$el.find('#dv_' + this.fieldname + ' ul');
this.$ul.off();
this.$ul.on('click', 'a.highlightselect', this.highlightPerson.bind(this));
this.$divselrem = this.$el.find('div')
this.$divselrem.off();
this.$divselrem.on('click', 'div span.select2choiceremove', this.deletePerson.bind(this));
},
me.clickscrolleventstoggle = function() {
$(document).on("mouseenter", ".srchpara ul li", function(e) {
$('.srchpara ul li').removeClass("active");
$(this).addClass("active");
});
},
me.dvkeyscroll = function(e) {
if (e.which == 13) { //Enter key pressed
//jquery
$('.srchpara ul li.active a.highlightselect').click();
}
},
me.dvkeyscrollup = function(e) {
console.log(e.which)
var $current = $('.srchpara ul li.active');
var $next;
if (e.keyCode == 38)
$next = $current.prev();
if (e.keyCode == 40)
$next = $current.next();
//console.log($next)
if ($next != undefined) {
if ($next.length > 0) {
//jquery
$('.srchpara ul li').removeClass('active');
$next.addClass('active');
}
}
},
me.addPerson = function() {
internar = []
internobj = {}
// this.fieldname = this.$input.data('multipleselect-autocomplete')
this.fieldval = this.$input.val()
internobj[this.fieldname] = this.fieldval.toLowerCase();
internar.push(internobj)
this.payload();
this.removefromlist();
this.remotefunc(this.fieldname).then(this.responsetransform)
},
me.deletePerson = function(event) {
var removecontent = $(event.currentTarget);
var key = $(removecontent).data('selKey')
var val = $(removecontent).data('selVal').toLowerCase();
this.removefilterdiv(removecontent, key, val)
this.change(this.callbackfunc)
this.$input.focus();
//console.log(removecontent)
},
me.removefilterdiv = function(arg, key, val) {
$(arg).parent().remove()
var interncon = this.basesearchar
interncon = interncon.filter(function(e) {
return e[key] != undefined
}).map(function(doctor) {
return {
[key]: doctor[key].remByVal(val)
}
})
this.updateNameById(this.basesearchar, key, interncon[0][key]);
if (interncon[0][key].length <= 0) {
this.basesearchar = datatransformutils.removeJsonAttrs(this.basesearchar, [key]);
}
this.basesearchar = this.basesearchar.filter(value => Object.keys(value).length !== 0);
},
me.highlightPerson = function(event) {
var removecontent = $(event.target).closest('li').find('a');
var key = $(removecontent).data('selKey')
var val = $(removecontent).data('selVal')
this.onsearchtext(key, val)
this.$input.focus();
this.change(this.callbackfunc)
},
me.onsearchtext = function(key, val) {
// $("#dv_" + key).remove();
this.$el.find('#dv_' + key + ' ').html(' ');
this.$el.find('#dv_' + key + ' ').hide();
//$("#dv_" + key).html(" ");
//$("#dv_" + key).hide();
// \"" + val + "\"
$("#cltrl_filter_" + key).val('');
this.assignsearchparams(key, val);
var interntags = this.rendertags(key, val)
//jquery
$("#cltrl_filter_chips_" + key).append(interntags)
},
me.rendertags = function(key, val) {
var divSpan = document.createElement("div");
divSpan.setAttribute("class", "selectchips");
divSpan.textContent = val.capitalize();
var closeSpan = document.createElement("span");
closeSpan.setAttribute("class", "select2choiceremove");
closeSpan.setAttribute("id", "cltrl_filter_span_" + key);
closeSpan.setAttribute("data-sel-key", key);
closeSpan.setAttribute("data-sel-val", val);
closeSpan.textContent = "x";
divSpan.appendChild(closeSpan)
return divSpan;
},
me.assignsearchparams = function(key, val) {
var internar = []
var basesearchobj = {}
if (isNaN(val)) {
val = val.toLowerCase()
internar.push(val)
} else {
internar.push(val)
}
//UPDATE
if (this.basesearchar.filter(function(e) {
return e[key] != undefined
}).length > 0) {
var interncon = this.basesearchar
interncon = interncon.filter(function(e) {
return e[key] != undefined
}).map(function(doctor) {
return {
[key]: doctor[key].concat(val)
}
})
this.updateNameById(this.basesearchar, key, interncon[0][key]);
} else {
// ADD
basesearchobj[key] = internar
this.basesearchar.push(basesearchobj);
basesearchobj = {}
}
},
me.updateNameById = function(obj, id, value) {
Object.keys(obj).some(function(key) {
if (obj[key][id] != undefined) {
obj[key][id] = value;
return true;
}
return true;
})
},
me.payload = function() {
this.filterparam.pageno = 0;
this.filterparam.pageSize = 20;
this.filterparam.searchtype = "Columnwise";
this.filterparam.searchparam = internar;
this.filterparam.searchparammetafilter = this.internbasearh
this.filterparam.ispaginate = true
this.base.datapayload = this.filterparam
this.internbasesearchar = this.basesearchar;
},
me.renderinputtag = function() {
var divSpaninput = document.createElement("input");
divSpaninput.setAttribute("type", "text");
divSpaninput.setAttribute("class", "form-control");
divSpaninput.setAttribute("class", "form-control-multiselect");
var ids = "cltrl_filter_" + this.fieldname;
divSpaninput.setAttribute("id", ids);
divSpaninput.setAttribute("placeholder", this.fieldname.capitalize());
this.$el.append(divSpaninput);
},
me.appendautopopulate = function(arg) {
var internsid = 'cltrl_filter_chips_' + this.fieldname;
var internsdvid = 'dv_' + this.fieldname;
var divSpanchips = document.createElement("div");
//srchpara
divSpanchips.setAttribute("id", internsid)
divSpanchips.setAttribute("class", "sidebyside")
var divSpansearch = document.createElement("div");
divSpansearch.setAttribute("id", internsdvid)
divSpansearch.setAttribute("class", "srchpara")
$(divSpansearch).insertAfter($(divSpanchips).insertBefore($(arg)));
},
me.removefromlist = function() {
if (this.basesearchar.length > 0) {
this.internbasearh.push(this.basesearchar)
this.internbasearh = datatransformutils.removeJsonAttrs(this.internbasearh[0], [this.fieldname])
this.internbasearh = (Object.keys(this.internbasearh[0]).length == 0 ? [] : this.internbasearh);
}
},
me.change = function(callback) {
callback(this.basesearchar)
},
me.responsetransform = function(data) {
var internset = me.removefromlistresp(data)
me.divautopopulate(internset);
me.bindEvents();
},
me.renderautopopulate = function(key, val) {
//var ultag = document.createElement("ul");
var litag = document.createElement("li");
var atag = document.createElement("a");
atag.setAttribute("class", "highlightselect");
atag.setAttribute("data-sel-key", key);
atag.setAttribute("data-sel-val", val);
atag.textContent = val.capitalize();
litag.appendChild(atag)
//ultag.appendChild(atag)
return litag;
},
me.divautopopulate = function(internset) {
var ultag = document.createElement("ul");
internset.forEach(function(obj) {
//var key=Object.keys(obj)
//var val=obj[Object.keys(obj)]
var key = obj.key;
var val = obj.text;
ultag.appendChild(me.renderautopopulate(key, val))
})
$("#dv_" + me.fieldname + "").show()
$("#dv_" + me.fieldname + "").html($(ultag));
internset = ""
$('.srchpara ul li').eq(0).addClass("active");
return true;
},
me.removefromlistresp = function(data) {
this.internset = data
//remove already selected items from select object !
if (this.internbasesearchar.length > 0) {
var toRem = this.internbasesearchar.map(function(a) {
return a[Object.keys(a)]
})[0]
//this.internset = this.internset.filter((el) => !toRem.includes(el[Object.keys(el)].toLowerCase()));
this.internset = this.internset.filter((el) => !toRem.includes(el.text.toLowerCase()));
}
return this.internset
},
me.onremoteupate = function(editcontent) {
editcontent.forEach(function(obj) {
me.onsearchtext(obj.key, obj.text);
})
}
return me;
};
.active {
background-color: #5897fb;
color: #ffffff!important;
}
.srchpara ul
{
-webkit-padding-start: 0px;
}
.form-control-multiselect {
box-shadow: none;
outline:none;
border-width: 0px;
}
.form-control-multiselect :focus {
box-shadow: none!important;
outline:none!important;
border-width: 0px;
}
.spanmul
{
background-color: white;
border: 1px solid #aaa;
border-radius: 4px;
cursor: text;
width:45%
}
.select2choiceremove {
color: #999;
cursor: pointer;
display: inline-block;
font-weight: 700;
margin-right: 2px;
}
.sidebyside
{
display: inline-block !important;
}
.selectchips {
background-color: #e4e4e4;
border: 1px solid #aaa;
border-radius: 4px;
cursor: default;
float: left;
margin-right: 5px;
margin-top: 5px;
padding: 0 5px;
display: inline-block !important;
}
.srchpara {
color: Black!important;
position: absolute!important;
background-color: white;
border-radius: 4px;
box-sizing: border-box;
z-index: 1000!important;
border: 1px solid #cccccc;
overflow-y: auto;
max-height: 400px;
}
.srchpara a {
display: block;
padding: 7px 12px;
}
/* srchpara*/
let multiselconfig = {
selectevent: '#inpfirst_name',
fieldkey: 'first_name',
remotefunc: dataset
}
var r = new multisel(multiselconfig, done)
r.init()
/*for assign values */
//y.onremoteupate(editval);
function done(data) {
console.log(data)
}
let editval = [{
"key":"last_name",
"text": "Ayonca",
}, {
"key":"last_name",
"text": "Ayakannu"
}]
function dataset(data) {
var interncontent = [{
"key":"last_name",
"text": "Ayonca",
}, {
"key":"last_name",
"text": "Ayakannu"
}, {
"key":"last_name",
"text": "Avishai"
}, {
"key":"last_name",
"text": "Augustine"
}]
return new Promise(function(resolve, reject) {
resolve(interncontent)
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment