Combo v6
This commit is contained in:
parent
c298205e2f
commit
0d4e769906
@salix/core/src/autocomplete
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)"
|
||||||
|
|
Loading…
Reference in New Issue