Javascript – Vì sao phải sử dụng Autocomplete dropdown? Với 1 list tầm 100 items thì bạn dùng Dropdown thì hợp lý.
Nhưng lớn hơn thì chẳng lẽ người dùng phải đi cuộn cắm đầu xuống tìm cho ra item đó sao? Quá ko hợp lý. Khi đó chúng ta sẽ phải nghĩ tới trường hợp cho người dùng gõ vào và auto Suggest cho người ta những item theo ý của người dùng.
Nào bắt tay vào làm việc nhé
I. Chuẩn bị:
- Jquery
- 1 File Js
- 1 File Css
II. Coding:
Coding JS
(function ($) {
$.fn.extend({
tAutoComplete: function (options) {
var that = $(this);
var _countPaging = 0;
var _countPagingSearch = 0;
var _combineId = that.attr("id");
var _divCoverId = 'dvCover' + _combineId;
var _divTestId = 'dvTest' + _combineId;
var _divCover = null;
var _divTest = null;
var _foundedItems = new Array();
var _coverDivTop = 0;
var _coverDivLeft = 0;
var _coverDivWidth = that.outerWidth();
var _body = $("body");
var _showMoreElement = $('<p class="TShowMore">MORE...</p>');
var _lowerArray = $.map(options.source, function (n, i) { return htmlDecode(n.toLowerCase()); });
//Settings list and the default values
var defaults = {
minChar: 60,
maxLength: 10,
numberOfRecords: 100,
maxHeightCss: 250,
source: new Array(),
// select: function (index, item) { },
};
// extend the options from pre-defined values:
var defaults = $.extend({
select: function () { }
}, arguments[0] || {});
var options = $.extend(defaults, options);
that.click(function (e) {
_coverDivTop = $(this).offset().top + $(this).outerHeight() + 1;
_coverDivLeft = $(this).offset().left;
var val = that.val().toLowerCase();;
if (val.length > 0) {
searchStringInArray(val);
} else {
GenerateParentDiv();
}
_divCover = _body.find("#" + _divCoverId);
});
that.blur(function () {
//// Check item exist in array
var t = '';
clearTimeout(t);
delay(function () {
var val = that.val().toLowerCase();
//alert(val);
var index = $.inArray(val, _lowerArray);
//alert(index);
if (index == -1) {
that.val('');
}
}, 20);
});
that.keyup(function (e) {
// Show list item
if (!~$.inArray(e.which, [13, 27, 38, 40, 37, 39])) {
var val = that.val().toLowerCase();
// Set Time after input
var t = '';
if (val.length >= options.minChars) {
clearTimeout(t);
delay(function () {
searchStringInArray(val);
}, 200);
} else {
//that.last_val = val;
//that.sc.hide();
}
}
});
that.keydown(function (e) {
if (~$.inArray(e.which, [38, 40, 13, 9])) {
if (event.keyCode == 38)
{
// Get current index of TSelected
_divCover = _body.find("#" + _divCoverId);
var $current = _divCover.find(".TSelected").first();
$current = $current.prev();
SetSelectedForItem(_divCover, $current);
}
if (event.keyCode == 40)
{
// Get current index of TSelected
_divCover = _body.find("#" + _divCoverId);
var $current = _divCover.find(".TSelected").first();
$current = $current.next();
SetSelectedForItem(_divCover, $current);
}
if (event.keyCode == 13 || event.keyCode == 9)
{
_divCover = _body.find("#" + _divCoverId);
var $current = _divCover.find(".TSelected").first();
if ($current.length > 0) {
that.val($current.text());
_divCover.hide();
if ($.isFunction(options.select)) {
options.select.call(this, that, { value: $(this).text() });
}
}
}
}
});
$(document).mouseup(function (e) {
var divCover = _body.find("#" + _divCoverId);
if (!divCover.is(e.target) // if the target of the click isn't the container...
&& divCover.has(e.target).length === 0) // ... nor a descendant of the container
{
divCover.hide();
}
});
function GenerateParentDiv() {
var _topItems = options.source.slice(0, options.numberOfRecords);
var _countItem = options.source.length / options.numberOfRecords;
var parent = $('<div id="' + _divCoverId + '" style="position:absolute; top:' + _coverDivTop + 'px; left:' + _coverDivLeft + 'px; width:' + (_coverDivWidth - 2) + 'px; background:white; border:1px solid #666;max-height:' + options.maxHeightCss + 'px; overflow-y: auto; overflow-x: hidden; z-index:1000;"></div>');
if (!_body.find("#" + _divCoverId).length > 0) {
// Reset value to default
_countPaging = 0;
// Append TOP element
$.each(_topItems, function (index, item) {
AppendItemToList(parent, item);
});
// Append show more link
var top = 0 + options.numberOfRecords;
if (_topItems.length > 0 && (options.source.length - top > 0)) {
AppendShowMoreItem(parent, _countPaging);
}
_body.append(parent);
_divCover = parent;
if (_topItems.length > 0) {
ShowDataDiv(parent);
// Focus to first item
FocusToFirstItem();
} else {
parent.hide();
}
} else {
// Reset value to default
_countPaging = 0;
_divCover = _body.find("#" + _divCoverId);
_divCover.empty();
// Append TOP element
$.each(_topItems, function (index, item) {
AppendItemToList(_divCover, item);
});
// Append show more link
// Append show more link
var top = 0 + options.numberOfRecords;
if (_topItems.length > 0 && (options.source.length - top > 0)) {
AppendShowMoreItem(_divCover, _countPaging);
}
if (_topItems.length > 0) {
ShowDataDiv(_divCover);
// Focus to first item
FocusToFirstItem();
}
}
}
function ShowMore(divTest) {
_countPaging++;
AppendMoreItem(divTest, _countPaging);
}
function AppendShowMoreItem(divTest, count) {
var showMoreLink = _showMoreElement;
showMoreLink.click(function () {
var showMoreElement = $(this);
$(this).remove();
ShowMore(divTest);
});
divTest.append(showMoreLink);
}
function AppendMoreItem(divTest, count) {
var bottom = count * options.numberOfRecords + 1;
var top = bottom + options.numberOfRecords;
var topItems = options.source.slice(bottom, top);
// Append all element
$.each(topItems, function (index, item) {
AppendItemToList(divTest, item);
});
if (topItems.length > 0 && (options.source.length - top > 0)) {
AppendShowMoreItem(divTest, count);
}
that.focus();
}
function AppendItemToList(divTest, item) {
var currentItem = $('<p class="THoverAble">' + item + '</p>');
currentItem.click(function () {
divTest.find(".TSelected").removeClass("TSelected");
$(this).addClass('TSelected');
that.val($(this).text());
divTest.hide();
if ($.isFunction(options.select)) {
options.select.call(this, that , { value: $(this).text() });
}
});
divTest.append(currentItem);
}
function searchStringInArray(str) {
// Reset all value to default
_countPagingSearch = 0;
_foundedItems = new Array();
var divTest = _body.find("#" + _divCoverId);
if (divTest.length < 1) {
// Create div Test
var parent = $('<div id="' + _divCoverId + '" style="position:absolute; top:' + _coverDivTop + 'px; left:' + _coverDivLeft + 'px; width:' + (_coverDivWidth - 2) + 'px; background:white; border:1px solid #666;max-height:' + options.maxHeightCss + 'px; overflow-y: auto; overflow-x: hidden; z-index:1000;"></div>');
_body.append(parent);
divTest = parent;
_divCover = parent;
} else {
_coverDivTop = that.offset().top + that.outerHeight() + 1;
_coverDivLeft = that.offset().left;
// Update css
divTest.css("top", _coverDivTop + "px");
divTest.css("left", _coverDivLeft + "px");
}
divTest.empty();
for (var j = 0; j < _lowerArray.length; j++) {
var text = _lowerArray[j];
var resultTest = text.indexOf(str) > -1;
if (resultTest) {
_foundedItems.push(options.source[j]);
}
}
var count = 0;
var bottom = count * options.numberOfRecords;
var top = bottom + options.numberOfRecords;
var topItems = _foundedItems.slice(bottom, top);
$.each(topItems, function (index, item) {
AppendItemToList(divTest, item);
});
if (topItems.length > 0 && (_foundedItems.length - top > 0)) {
AppendShowMoreItemSearch(divTest, count);
}
if (topItems.length > 0) {
ShowDataDiv(divTest);
FocusToFirstItem();
} else {
divTest.hide();
}
}
function AppendShowMoreItemSearch(divTest, count) {
var showMoreLink = _showMoreElement;
showMoreLink.click(function () {
var showMoreElement = $(this);
$(this).remove();
ShowMoreSearch(divTest);
});
divTest.append(showMoreLink);
}
function ShowMoreSearch(divTest) {
_countPagingSearch++;
AppendMoreItemSearch(divTest, _countPagingSearch);
}
function AppendMoreItemSearch(divTest, count) {
var bottom = count * options.numberOfRecords + 1;
var top = bottom + options.numberOfRecords;
var topItems = _foundedItems.slice(bottom, top);
// Append all element
$.each(topItems, function (index, item) {
AppendItemToList(divTest, item);
});
if (topItems.length > 0 && (_foundedItems.length - top > 0)) {
AppendShowMoreItemSearch(divTest, count);
}
that.focus();
}
function FocusToFirstItem() {
_divCover = _body.find("#" + _divCoverId);
_divCover.find(".THoverAble").removeClass("TSelected");
var first = _divCover.find(".THoverAble").first();
first.addClass("TSelected");
}
function ShowDataDiv(divData) {
divData.show();
// Set css
divData.css({ "top": _coverDivTop + "px", "left": _coverDivLeft + "px" });
$(divData).scrollTop(0);
}
function SetSelectedForItem(divCover, currentItem) {
currentItem = $(currentItem);
divCover = $(divCover);
if (currentItem.length > 0 && currentItem.hasClass("THoverAble")) {
divCover.find(".TSelected").removeClass("TSelected");
currentItem.addClass("TSelected");
that.val(currentItem.text());
$(divCover).scrollTop(currentItem.index() * currentItem.outerHeight() - (currentItem.outerHeight() + 10));
}
}
function htmlDecode(value) {
return $('<div/>').html(value).text();
}
}
});
})(jQuery);
Coding CSS
.TDropdownDiv{
position:relative;
}
.TDropdownUL{
position:absolute;
width:99%;
display:none;
border-left: 1px solid #006498;
border-right: 1px solid #006498;
border-bottom: 1px solid #006498;
background:white;
z-index:999;
max-height:250px;
overflow-y:scroll;
}
.TDropdownUL li {
list-style:none;
position:relative;
padding-left:3px;
color:black;
}
.TDropdownUL li:hover{
background: #3399ff;
color:white;
}
.TDropdownUL li.TSelected{
background: #3399ff;
color:white;
}
.TDropdownUL li.Li_Header{
background: #cacaca;
color:#666;
font-weight:bold;
}
.TDropdownButton{
border:none;
position:absolute;
width:17px !important;
height:18px;
top:1px;
right:3px;
background: url('Images/btDropdown.png') no-repeat;
}
.LiValue{
display:block;
}
.LiValue:hover{
cursor:default;
}
.THoverAble{
padding:0px 2px;
}
.TShowMore{
color:blue;
text-align:right;
cursor:pointer;
text-decoration:underline;
text-transform:lowercase;
padding-right: 10px;
}
Tạo dữ liệu mẫu
$(document).ready(function(){
subNames = new Array();
@foreach (var item in Model.Subdivisions)
{
@:subNames.push('@item.SubName');
}
$("#SubName").tAutoComplete({
minChars:0,
minLength: 0,
source: subNames,
numberOfRecords: 200,
maxHeightCss: 250,
select: function (object, data) {
var _this = $(object);
//DoMoreThingWith(_this);
}
});
});
Chạy và xem kết quả
Các bạn thấy bài viết thế nào? 🙂
Cho mình ý kiến nhé