This commit is contained in:
Juan Ferrer Toribio 2017-01-20 12:43:58 +01:00
parent c298205e2f
commit 0d4e769906
2 changed files with 115 additions and 55 deletions

View File

@ -24,12 +24,7 @@ function template($element, $attrs, normalizer, resolve) {
controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover']; controller.$inject = ['$http', '$element', '$attrs', '$scope', '$parse', '$document', 'vnPopover'];
function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) { function controller($http, $element, $attrs, $scope, $parse, $document, popoverProvider) {
let input = $element.find('input')[0];
let popover = null;
let data = [];
let locked = false; let locked = false;
let timeoutId = null;
let activeOption = -1;
$scope.$watch($attrs.model, (newValue) => { $scope.$watch($attrs.model, (newValue) => {
if(!locked) { if(!locked) {
@ -45,8 +40,43 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
componentHandler.upgradeElement($element[0].firstChild); componentHandler.upgradeElement($element[0].firstChild);
Object.assign(this, { Object.assign(this, {
loadData: function(where, callback) { init: function() {
if(!where) where = {}; 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 = {}; let fields = {};
fields[this.valueField] = true; fields[this.valueField] = true;
fields[this.showField] = true; fields[this.showField] = true;
@ -55,48 +85,68 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
fields: fields, fields: fields,
where: where, where: where,
order: `${this.showField} ASC`, order: `${this.showField} ASC`,
limit: 10 limit: this.maxRows
}; };
// Envia la petición
this.lastRequest = value;
let json = JSON.stringify(filter); let json = JSON.stringify(filter);
$http.get(`${this.url}?filter=${json}`).then( $http.get(`${this.url}?filter=${json}`).then(
json => { json => this.setData(json.data),
data = json.data; json => this.setData([])
if (callback) callback();
},
json => {
data = [];
}
); );
}, },
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() { showPopover: function() {
//FIXME //FIXME
this.hidePopover(); this.hidePopover();
popover = $document[0].createElement('ul'); let popover = $document[0].createElement('ul');
popover.addEventListener('click', popover.addEventListener('click',
(e) => this.onPopoverClick(e)); (e) => this.onPopoverClick(e));
popover.addEventListener('mousedown', popover.addEventListener('mousedown',
(e) => this.onPopoverMousedown(e)); (e) => this.onPopoverMousedown(e));
popover.className = 'vn-autocomplete-popover'; popover.className = 'vn-autocomplete-popover';
let data = this.showData;
for(let i = 0; i < data.length; i++) { for(let i = 0; i < data.length; i++) {
let li = $document[0].createElement('li'); let li = $document[0].createElement('li');
li.appendChild($document[0].createTextNode(data[i][this.showField])); li.appendChild($document[0].createTextNode(data[i][this.showField]));
popover.appendChild(li); popover.appendChild(li);
} }
popoverProvider.show(popover, input); popoverProvider.show(popover, this.input);
this.popover = popover;
}, },
hidePopover: function() { hidePopover: function() {
if(!popover) return; if(!this.popover) return;
activeOption = -1; this.activeOption = -1;
popoverProvider.hide(); popoverProvider.hide();
popover = null; this.popover = null;
}, },
onPopoverClick: function(event) { onPopoverClick: function(event) {
let childs = popover.childNodes; let childs = this.popover.childNodes;
for(let i = 0; i < childs.length; i++) for(let i = 0; i < childs.length; i++)
if(childs[i] === event.target) { if(childs[i] === event.target) {
this.selectOptionByIndex(i); this.selectOptionByIndex(i);
@ -110,45 +160,48 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
event.preventDefault(); event.preventDefault();
}, },
onFocus: function() { onFocus: function() {
input.select(); this.hasFocus = true;
this.input.select();
this.showPopover(); this.showPopover();
}, },
onBlur: function() { onBlur: function() {
this.hasFocus = false;
this.hidePopover(); this.hidePopover();
}, },
onKeypress: function(event) { onKeydown: function(event) {
switch(event.keyCode) { switch(event.keyCode) {
case 13: // Enter case 13: // Enter
if(popover && activeOption != -1) { if(this.popover && this.activeOption != -1) {
this.selectOptionByIndex(activeOption); this.putValue(this.showData[this.activeOption]);
this.hidePopover(); this.hidePopover();
} }
return; break;
case 27: // Escape
this.hidePopover();
break;
case 38: // Arrow up case 38: // Arrow up
this.activateOption(activeOption-1); this.activateOption(this.activeOption-1);
return; break;
case 40: // Arrow down case 40: // Arrow down
this.activateOption(activeOption+1); this.activateOption(this.activeOption+1);
break;
default:
return; return;
} }
event.preventDefault();
}, },
onClick: function(event) { onClick: function(event) {
if(!popover) if(!this.popover) this.showPopover();
this.showPopover();
}, },
onKeyup: function(event) { onKeyup: function(event) {
if(!this.isKeycodePrintable(event.keyCode)) if(!this.isKeycodePrintable(event.keyCode)) return;
return; if(this.timeoutId) clearTimeout(this.timeoutId);
this.timeoutId = setTimeout(() => this.onTimeout(), this.filterDelay);
if(timeoutId) clearTimeout(timeoutId);
timeoutId = setTimeout(() => this.onTimeout(), 300);
}, },
onTimeout: function() { onTimeout: function() {
let value = input.value; this.loadData(this.input.value);
let filter = {}; this.timeoutId = null;
filter[this.showField] = {ilike: value};
this.loadData(filter, () => this.showPopover());
timeoutId = null;
}, },
isKeycodePrintable: function(keyCode) { isKeycodePrintable: function(keyCode) {
return keyCode == 32 // Spacebar return keyCode == 32 // Spacebar
@ -160,13 +213,13 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
|| (keyCode > 218 && keyCode < 223); // [\]' || (keyCode > 218 && keyCode < 223); // [\]'
}, },
activateOption: function(index) { activateOption: function(index) {
if(!popover) if(!this.popover)
this.showPopover(); this.showPopover();
let childs = popover.childNodes; let childs = this.popover.childNodes;
if(activeOption >= 0) if(this.activeOption >= 0)
childs[activeOption].className = ''; childs[this.activeOption].className = '';
if(index >= childs.length) if(index >= childs.length)
index = 0; index = 0;
@ -176,30 +229,37 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
if (index >= 0) if (index >= 0)
childs[index].className = 'active'; childs[index].className = 'active';
activeOption = index; this.activeOption = index;
}, },
setValue: function(value) { setValue: function(value) {
let index = -1; let data = this.data;
if(value && data) if(value && data)
for(let i = 0; i < data.length; i++) for(let i = 0; i < data.length; i++)
if(data[i][this.valueField] == value) { if(data[i][this.valueField] == value) {
this.selectOptionByIndex(i); this.putValue(data[i]);
return; return;
} }
this.selectOptionByIndex(-1); this.putValue(null);
}, },
selectOptionByIndex: function(index) { 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; let value;
if(index >= 0 && index < data.length) { if(item) {
let item = data[index]; this.input.value = item[this.showField];
input.value = item[this.showField];
value = item[this.valueField]; value = item[this.valueField];
} }
else { else {
input.value = ''; this.input.value = '';
value = undefined; value = undefined;
} }
@ -215,5 +275,5 @@ function controller($http, $element, $attrs, $scope, $parse, $document, popoverP
} }
}); });
this.loadData(null, () => this.setValue(this.model)); this.init();
} }

View File

@ -5,7 +5,7 @@
rule="*[rule]*" rule="*[rule]*"
*[enabled]* *[enabled]*
*[focus]* *[focus]*
ng-keypress="$ctrl.onKeypress($event)" ng-keydown="$ctrl.onKeydown($event)"
ng-click="$ctrl.onClick($event)" ng-click="$ctrl.onClick($event)"
ng-keyup="$ctrl.onKeyup($event)" ng-keyup="$ctrl.onKeyup($event)"
ng-focus="$ctrl.onFocus($event)" ng-focus="$ctrl.onFocus($event)"