It seems that the combo dropdown (select) is always positioned below and left justified to the combo itself. This causes part of the dropdown to be off screen if the combo is itself near the right edge or bottom of the visible form.
It also seems that there were autoPositioning capabilities prior to version 4 that were removed.
How can I use a combo anywhere on the screen and have the dropdown be visible to the user?
If you are using fullscreen init, combo must change the popup list position when there is no enough space at the bottom of the screen.
Please check snippet.dhtmlx.com/d71f2ec4f
I’m using absolute positioning of the combo in the form, along with multicolumn select contents so that the dropdown is wider than the combo itself. When the combo is near the right edge of the form, then the dropdown (which is left justified with the combo) is largely off screen. I’ve attached an image file showing this problem.
I’ve been looking into this mod and discovered an error in your existing code…at least in v4.6.1
line 1348 in dhtmlxcombo.js is:
var onTop = Math.max(0, Math.floor((by+hh-s.top)/this.conf.item_h));
but should be:
var onTop = Math.max(0, Math.floor((by-hh-s.top)/this.conf.item_h));
That is, the header height (hh) must be subtracted from the available height, not added to it. I’ve tested and confirmed this fix.
Below are my overrides to handle positioning of the select list and account for screen boundaries:
/*
make combo select positioning account for edges of visible browser page
start combo select positioning change
from v4.6.1 dhtmlx_debug.js
*/
dhtmlXCombo.prototype._showList = function(autoHide) {
if (this._getListVisibleCount() == 0) {
if (autoHide && this._isListVisible()) this._hideList();
return;
}
if (this._isListVisible()) {
this._checkListHeight();
return;
}
this.list.style.zIndex = window.dhx4.zim.reserve(this.conf.list_zi_id); // get new z-index
if (this.hdr != null && this.conf.template.header == true) this.hdr.style.zIndex = Number(this.list.style.zIndex)+1;
this.list.style.visibility = "hidden";
this.list.style.display = "";
if (this.hdr != null && this.conf.template.header == true) {
this.hdr.style.visibility = this.list.style.visibility;
this.hdr.style.display = this.list.style.display;
}
// position
var h0 = (this.hdr != null && this.conf.template.header == true ? this.hdr.offsetHeight : 0);
/*
REW: adjust left to prevent pushing contents of list off screen to the right,
but only to the left screen boundary and
limit list width to available screen width so that scrollbar is always accessible
*/
var lWidth = Math.max(this.conf.opts_width||this.conf.col_w||0, this.conf.combo_width);
var s = window.dhx4.screenDim();
lWidth = Math.min(s.right,lWidth);
this.list.style.width = lWidth+"px";
//this.list.style.width = Math.max(this.conf.opts_width||this.conf.col_w||0, this.conf.combo_width)+"px";
this.list.style.top = window.dhx4.absTop(this.base)+h0+this.base.offsetHeight-1+"px";
var absLeft = window.dhx4.absLeft(this.base);
var leftAdjust = (absLeft+lWidth < s.right ? 0:Math.min(lWidth - (s.right - absLeft - 4), absLeft));
this.list.style.left = (window.dhx4.absLeft(this.base)-leftAdjust)+"px";
if (this.hdr != null && this.conf.template.header == true) {
this.hdr.style.width = this.list.style.width;
this.hdr.style.left = this.list.style.left;
this.hdr.style.top = parseInt(this.list.style.top)-h0+"px";
}
// height
this._checkListHeight();
// check bottom overlay
this.list.style.visibility = "visible";
if (this.hdr != null && this.conf.template.header == true) this.hdr.style.visibility = "visible";
this.callEvent("onOpen",[]);
};
dhtmlXCombo.prototype._checkListHeight = function() {
/*
REW: appears to try to put list on bottom by reducing the num of items shown down to opts_count_min,
and only moving above the base if the min fails to fit. The onTop calc above was wrong.
original values: opts_count_min: 3; opts_count: 8;
Don't want to show only 3 items just to display below the combo, rather show a usable quantity above
Changes:
opts_count_min: 8;
opts_count: 15;
*/
this.conf.opts_count_min = 8; //override
this.conf.opts_count = 15; //override
if (!this._isListVisible()) return;
if (this.conf.item_h == null) {
var item = this.list.firstChild;
while (item != null) {
if (item.style.display == "") {
this.conf.item_h = item.offsetHeight + (this.hdr != null ? -1 : 0); // multicol rows have -1px margin
item = null;
} else {
item = item.nextSibling;
}
}
item = null;
}
var s = window.dhx4.screenDim();
var by = window.dhx4.absTop(this.base);
var bh = this.base.offsetHeight;
var hh = (this.hdr!=null&&this.conf.template.header==true?this.hdr.offsetHeight:0); // header_height
//REW corrected 12.10.2016
var onTop = Math.max(0, Math.floor((by-hh-s.top)/this.conf.item_h));
var onBottom = Math.max(0, Math.floor((s.bottom-(by+bh+hh))/this.conf.item_h));
var itemsCount = this._getListVisibleCount();
// top/bottom detect
if (onBottom < Math.min(this.conf.opts_count_min, itemsCount) && onTop > onBottom) onBottom = null;
var itemsToShow = Math.min((onBottom==null?onTop:onBottom), this.conf.opts_count, itemsCount);
var h = (itemsToShow<itemsCount?(itemsToShow*this.conf.item_h)+"px":"");
var ofs = this.conf.sp[this.conf.skin][this.hdr!=null&&this.conf.template.header==true?"hdr_ofs":"list_ofs"];
this.list.style.height = h;
this.list.style.top = (onBottom==null?by-this.list.offsetHeight+ofs:by+bh+hh-ofs)+"px";
if (this.hdr != null && this.conf.template.header == true) this.hdr.style.top = (onBottom==null?by-hh-this.list.offsetHeight+ofs:by+bh-ofs)+"px";
};
Get a guaranteed answer from DHTMLX technical support team
under the most suitable support plan