Last active
May 15, 2018 15:08
-
-
Save matt212/0418912d8f4c1b7d1630434fa27f9974 to your computer and use it in GitHub Desktop.
Custom Modular Multiselect plugin and its implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.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*/ | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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