From 0d4e769906fd43af92adef63b8d3308a8aea2bb1 Mon Sep 17 00:00:00 2001 From: Juan Ferrer Toribio Date: Fri, 20 Jan 2017 12:43:58 +0100 Subject: [PATCH] Combo v6 --- @salix/core/src/autocomplete/index.js | 168 +++++++++++++------- @salix/core/src/autocomplete/index.mdl.html | 2 +- 2 files changed, 115 insertions(+), 55 deletions(-) diff --git a/@salix/core/src/autocomplete/index.js b/@salix/core/src/autocomplete/index.js index a53d1d27e..4fc9168ac 100644 --- a/@salix/core/src/autocomplete/index.js +++ b/@salix/core/src/autocomplete/index.js @@ -24,12 +24,7 @@ function template($element, $attrs, normalizer, resolve) { controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover']; function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) { - let input = $element.find('input')[0]; - let popover = null; - let data = []; let locked = false; - let timeoutId = null; - let activeOption = -1; $scope.$watch($attrs.model, (newValue) => { if(!locked) { @@ -45,8 +40,43 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP componentHandler.upgradeElement($element[0].firstChild); Object.assign(this, { - loadData: function(where, callback) { - if(!where) where = {}; + init: function() { + this.input = $element.find('input')[0]; + this.popover = null; + this.data = null; + this.showData = null; + this.timeoutId = null; + this.activeOption = -1; + this.lastSearch = null; + this.lastRequest = null; + this.maxRows = 10; + this.filterDelay = 350; + this.loadData(); + }, + loadData: function(value) { + // Optimiza la peticiĆ³n + + let lastSearch = this.lastSearch; + if(lastSearch === value) return; + this.lastSearch = value; + + let lastRequest = this.lastRequest; + let requestWillSame = ( + this.data && value && lastRequest + && this.data.length < this.maxRows + && value.substr(0, lastRequest.length) == lastRequest + ); + + if(requestWillSame) { + this.localFilter(value); + return; + } + + // Genera el filtro + + let where = {}; + if(value) where[this.showField] = {ilike: value}; + let fields = {}; fields[this.valueField] = true; fields[this.showField] = true; @@ -55,48 +85,68 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP fields: fields, where: where, order: `${this.showField} ASC`, - limit: 10 + limit: this.maxRows }; + // Envia la peticiĆ³n + + this.lastRequest = value; let json = JSON.stringify(filter); $http.get(`${this.url}?filter=${json}`).then( - json => { - data = json.data; - if (callback) callback(); - }, - json => { - data = []; - } + json => this.setData(json.data), + json => this.setData([]) ); }, + setData: function(data) { + this.data = data; + this.setShowData(this.data); + }, + localFilter: function(value) { + let regex = new RegExp(value, 'i'); + let data = this.data.filter((item) => { + return regex.test(item[this.showField]); + }); + this.setShowData(data); + }, + setShowData: function(data) { + this.showData = data; + + if(this.hasFocus) + this.showPopover(); + else + this.setValue(this.model); + }, showPopover: function() { //FIXME this.hidePopover(); - popover = $document[0].createElement('ul'); + let popover = $document[0].createElement('ul'); popover.addEventListener('click', (e) => this.onPopoverClick(e)); popover.addEventListener('mousedown', (e) => this.onPopoverMousedown(e)); popover.className = 'vn-autocomplete-popover'; + let data = this.showData; + for(let i = 0; i < data.length; i++) { let li = $document[0].createElement('li'); li.appendChild($document[0].createTextNode(data[i][this.showField])); popover.appendChild(li); } - popoverProvider.show(popover, input); + popoverProvider.show(popover, this.input); + this.popover = popover; }, hidePopover: function() { - if(!popover) return; - activeOption = -1; + if(!this.popover) return; + this.activeOption = -1; popoverProvider.hide(); - popover = null; + this.popover = null; }, onPopoverClick: function(event) { - let childs = popover.childNodes; + let childs = this.popover.childNodes; for(let i = 0; i < childs.length; i++) if(childs[i] === event.target) { this.selectOptionByIndex(i); @@ -110,45 +160,48 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP event.preventDefault(); }, onFocus: function() { - input.select(); + this.hasFocus = true; + this.input.select(); this.showPopover(); }, onBlur: function() { + this.hasFocus = false; this.hidePopover(); }, - onKeypress: function(event) { + onKeydown: function(event) { switch(event.keyCode) { case 13: // Enter - if(popover && activeOption != -1) { - this.selectOptionByIndex(activeOption); + if(this.popover && this.activeOption != -1) { + this.putValue(this.showData[this.activeOption]); this.hidePopover(); } - return; + break; + case 27: // Escape + this.hidePopover(); + break; case 38: // Arrow up - this.activateOption(activeOption-1); - return; + this.activateOption(this.activeOption-1); + break; case 40: // Arrow down - this.activateOption(activeOption+1); + this.activateOption(this.activeOption+1); + break; + default: return; } + + event.preventDefault(); }, onClick: function(event) { - if(!popover) - this.showPopover(); + if(!this.popover) this.showPopover(); }, onKeyup: function(event) { - if(!this.isKeycodePrintable(event.keyCode)) - return; - - if(timeoutId) clearTimeout(timeoutId); - timeoutId = setTimeout(() => this.onTimeout(), 300); + if(!this.isKeycodePrintable(event.keyCode)) return; + if(this.timeoutId) clearTimeout(this.timeoutId); + this.timeoutId = setTimeout(() => this.onTimeout(), this.filterDelay); }, onTimeout: function() { - let value = input.value; - let filter = {}; - filter[this.showField] = {ilike: value}; - this.loadData(filter, () => this.showPopover()); - timeoutId = null; + this.loadData(this.input.value); + this.timeoutId = null; }, isKeycodePrintable: function(keyCode) { return keyCode == 32 // Spacebar @@ -160,13 +213,13 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP || (keyCode > 218 && keyCode < 223); // [\]' }, activateOption: function(index) { - if(!popover) + if(!this.popover) this.showPopover(); - let childs = popover.childNodes; + let childs = this.popover.childNodes; - if(activeOption >= 0) - childs[activeOption].className = ''; + if(this.activeOption >= 0) + childs[this.activeOption].className = ''; if(index >= childs.length) index = 0; @@ -176,30 +229,37 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP if (index >= 0) childs[index].className = 'active'; - activeOption = index; + this.activeOption = index; }, setValue: function(value) { - let index = -1; + let data = this.data; if(value && data) for(let i = 0; i < data.length; i++) if(data[i][this.valueField] == value) { - this.selectOptionByIndex(i); + this.putValue(data[i]); return; } - this.selectOptionByIndex(-1); + this.putValue(null); }, selectOptionByIndex: function(index) { + let data = this.data; + + if(data && index >= 0 && index < data.length) + this.putValue(data[index]); + else + this.putValue(null); + }, + putValue: function(item) { let value; - if(index >= 0 && index < data.length) { - let item = data[index]; - input.value = item[this.showField]; + if(item) { + this.input.value = item[this.showField]; value = item[this.valueField]; } else { - input.value = ''; + this.input.value = ''; value = undefined; } @@ -215,5 +275,5 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP } }); - this.loadData(null, () => this.setValue(this.model)); + this.init(); } diff --git a/@salix/core/src/autocomplete/index.mdl.html b/@salix/core/src/autocomplete/index.mdl.html index 160659871..bef534feb 100644 --- a/@salix/core/src/autocomplete/index.mdl.html +++ b/@salix/core/src/autocomplete/index.mdl.html @@ -5,7 +5,7 @@ rule="*[rule]*" *[enabled]* *[focus]* - ng-keypress="$ctrl.onKeypress($event)" + ng-keydown="$ctrl.onKeydown($event)" ng-click="$ctrl.onClick($event)" ng-keyup="$ctrl.onKeyup($event)" ng-focus="$ctrl.onFocus($event)"