2018-02-10 15:18:01 +00:00
|
|
|
import ngModule from '../../module';
|
2018-03-26 10:24:34 +00:00
|
|
|
import Input from '../../lib/input';
|
2018-05-08 07:58:49 +00:00
|
|
|
import asignProps from '../../lib/asign-props';
|
2017-09-13 12:59:58 +00:00
|
|
|
import './style.scss';
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
/**
|
|
|
|
* Input with option selector.
|
|
|
|
*
|
|
|
|
* @property {String} valueField The data field name that should be shown
|
|
|
|
* @property {String} showFiled The data field name that should be used as value
|
|
|
|
* @property {Array} data Static data for the autocomplete
|
|
|
|
* @property {Object} intialData A initial data to avoid the server request used to get the selection
|
|
|
|
* @property {Boolean} multiple Wether to allow multiple selection
|
|
|
|
*/
|
2018-03-26 10:24:34 +00:00
|
|
|
export default class Autocomplete extends Input {
|
2018-03-09 13:15:30 +00:00
|
|
|
constructor($element, $scope, $http, $transclude) {
|
|
|
|
super($element, $scope);
|
2017-09-13 12:59:58 +00:00
|
|
|
this.$http = $http;
|
2018-03-09 13:15:30 +00:00
|
|
|
this.$transclude = $transclude;
|
|
|
|
|
|
|
|
this._field = undefined;
|
|
|
|
this._selection = null;
|
2018-01-29 11:37:54 +00:00
|
|
|
this.valueField = 'id';
|
2018-03-09 13:15:30 +00:00
|
|
|
this.showField = 'name';
|
2017-09-20 11:52:53 +00:00
|
|
|
this._multiField = [];
|
2017-09-21 11:10:30 +00:00
|
|
|
this.readonly = true;
|
2018-01-24 07:42:57 +00:00
|
|
|
this.form = null;
|
2018-03-09 13:15:30 +00:00
|
|
|
this.input = this.element.querySelector('.mdl-textfield__input');
|
2017-09-13 12:59:58 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
componentHandler.upgradeElement(
|
|
|
|
this.element.querySelector('.mdl-textfield'));
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
2017-11-13 21:15:44 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
/**
|
|
|
|
* @type {any} The autocomplete value.
|
|
|
|
*/
|
|
|
|
get field() {
|
|
|
|
return this._field;
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
set field(value) {
|
|
|
|
if (angular.equals(value, this._field))
|
|
|
|
return;
|
2017-09-13 12:59:58 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
this._field = value;
|
|
|
|
this.refreshSelection();
|
2017-09-20 11:52:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (this.onChange)
|
2018-04-04 13:03:13 +00:00
|
|
|
this.onChange({value});
|
2018-03-09 13:15:30 +00:00
|
|
|
}
|
2017-09-20 11:52:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
/**
|
|
|
|
* @type {Object} The selected data object, you can use this property
|
|
|
|
* to prevent requests to display the initial value.
|
|
|
|
*/
|
|
|
|
get selection() {
|
|
|
|
return this._selection;
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
set selection(value) {
|
|
|
|
this._selection = value;
|
|
|
|
this.refreshDisplayed();
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
2017-11-13 21:15:44 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
selectionIsValid(selection) {
|
|
|
|
return selection
|
|
|
|
&& selection[this.valueField] == this._field
|
|
|
|
&& selection[this.showField] != null;
|
|
|
|
}
|
2017-09-20 09:50:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
refreshSelection() {
|
|
|
|
if (this.selectionIsValid(this._selection))
|
|
|
|
return;
|
2017-09-20 09:50:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
let value = this._field;
|
2017-09-20 11:52:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (value && this.valueField && this.showField) {
|
|
|
|
if (this.selectionIsValid(this.initialData)) {
|
|
|
|
this.selection = this.initialData;
|
|
|
|
return;
|
2017-10-03 05:10:37 +00:00
|
|
|
}
|
2017-09-20 09:50:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
let data = this.data;
|
2017-09-20 11:52:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (!data && this.$.dropDown)
|
|
|
|
data = this.$.dropDown.$.model.data;
|
2017-09-20 09:50:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (data)
|
2017-09-20 09:50:53 +00:00
|
|
|
for (let i = 0; i < data.length; i++)
|
|
|
|
if (data[i][this.valueField] === value) {
|
2018-03-09 13:15:30 +00:00
|
|
|
this.selection = data[i];
|
2017-09-20 09:50:53 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (this.url) {
|
|
|
|
this.requestSelection(value);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
this.selection = null;
|
2017-09-20 09:50:53 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
requestSelection(value) {
|
2017-09-20 09:50:53 +00:00
|
|
|
let where = {};
|
2018-03-09 13:15:30 +00:00
|
|
|
|
|
|
|
if (this.multiple)
|
|
|
|
where[this.valueField] = {inq: this.field};
|
|
|
|
else
|
|
|
|
where[this.valueField] = value;
|
2017-09-20 09:50:53 +00:00
|
|
|
|
|
|
|
let filter = {
|
2018-03-09 13:15:30 +00:00
|
|
|
fields: this.getFields(),
|
2017-09-20 09:50:53 +00:00
|
|
|
where: where
|
|
|
|
};
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
let json = encodeURIComponent(JSON.stringify(filter));
|
2017-09-20 09:50:53 +00:00
|
|
|
this.$http.get(`${this.url}?filter=${json}`).then(
|
2018-03-09 13:15:30 +00:00
|
|
|
json => this.onSelectionRequest(json.data),
|
|
|
|
() => this.onSelectionRequest(null)
|
2017-09-20 09:50:53 +00:00
|
|
|
);
|
|
|
|
}
|
2017-11-13 21:15:44 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
onSelectionRequest(data) {
|
|
|
|
if (data && data.length > 0) {
|
|
|
|
if (this.multiple)
|
|
|
|
this.selection = data;
|
|
|
|
else
|
|
|
|
this.selection = data[0];
|
2018-04-18 12:44:07 +00:00
|
|
|
} else {
|
|
|
|
let selection = {};
|
|
|
|
selection[this.showField] = this._field;
|
|
|
|
selection[this.valueField] = this._field;
|
|
|
|
this.selection = selection;
|
|
|
|
}
|
2017-09-20 09:50:53 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
refreshDisplayed() {
|
|
|
|
let display = '';
|
|
|
|
|
|
|
|
if (this._selection && this.showField) {
|
|
|
|
if (this.multiple && Array.isArray(this._selection)) {
|
|
|
|
for (var item of this._selection) {
|
|
|
|
if (display.length > 0) display += ', ';
|
|
|
|
display += item[this.showField];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
display = this._selection[this.showField];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.input.value = display;
|
|
|
|
this.mdlUpdate();
|
2017-09-20 09:50:53 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
getFields() {
|
|
|
|
let fields = [];
|
|
|
|
fields.push(this.valueField);
|
|
|
|
fields.push(this.showField);
|
2017-09-20 09:50:53 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
if (this.selectFields)
|
|
|
|
for (let field of this.selectFields)
|
|
|
|
fields.push(field);
|
2017-09-20 09:50:53 +00:00
|
|
|
|
|
|
|
return fields;
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
mdlUpdate() {
|
|
|
|
let field = this.element.querySelector('.mdl-textfield');
|
|
|
|
let mdlField = field.MaterialTextfield;
|
|
|
|
if (mdlField) mdlField.updateClasses_();
|
2018-01-29 11:37:54 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
setValue(value) {
|
|
|
|
this.field = value;
|
|
|
|
if (this.form) this.form.$setDirty();
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
2017-11-13 21:15:44 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
onDropDownSelect(value) {
|
|
|
|
this.setValue(value);
|
|
|
|
this.field = value;
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
2018-03-09 13:15:30 +00:00
|
|
|
|
|
|
|
onClearClick(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.setValue(null);
|
2018-01-24 07:42:57 +00:00
|
|
|
}
|
2017-11-13 21:15:44 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
onKeyDown(event) {
|
|
|
|
if (event.defaultPrevented) return;
|
2017-09-13 12:59:58 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
switch (event.keyCode) {
|
|
|
|
case 38: // Up
|
|
|
|
case 40: // Down
|
|
|
|
case 13: // Enter
|
|
|
|
this.showDropDown();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (event.key.length == 1)
|
|
|
|
this.showDropDown(event.key);
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
2017-09-13 12:59:58 +00:00
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
event.preventDefault();
|
2017-09-14 11:40:55 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
onMouseDown(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
this.showDropDown();
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
|
|
|
|
2018-03-09 13:15:30 +00:00
|
|
|
showDropDown(search) {
|
|
|
|
Object.assign(this.$.dropDown.$.model, {
|
|
|
|
url: this.url,
|
|
|
|
staticData: this.data
|
|
|
|
});
|
2017-11-09 09:11:59 +00:00
|
|
|
|
2018-05-08 07:58:49 +00:00
|
|
|
asignProps(this, this.$.dropDown, [
|
|
|
|
'valueField',
|
|
|
|
'showField',
|
|
|
|
'where',
|
|
|
|
'order',
|
|
|
|
'showFilter',
|
|
|
|
'multiple',
|
|
|
|
'limit',
|
|
|
|
'$transclude'
|
|
|
|
]);
|
|
|
|
|
|
|
|
this.$.dropDown.selectFields = this.getFields();
|
|
|
|
this.$.dropDown.parent = this.input;
|
2018-03-09 13:15:30 +00:00
|
|
|
this.$.dropDown.show(search);
|
|
|
|
}
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
2018-03-09 13:15:30 +00:00
|
|
|
Autocomplete.$inject = ['$element', '$scope', '$http', '$transclude'];
|
2017-09-13 12:59:58 +00:00
|
|
|
|
2018-02-10 15:18:01 +00:00
|
|
|
ngModule.component('vnAutocomplete', {
|
2017-09-13 12:59:58 +00:00
|
|
|
template: require('./autocomplete.html'),
|
|
|
|
controller: Autocomplete,
|
|
|
|
bindings: {
|
|
|
|
url: '@?',
|
2018-03-09 13:15:30 +00:00
|
|
|
data: '<?',
|
2017-09-13 12:59:58 +00:00
|
|
|
showField: '@?',
|
|
|
|
valueField: '@?',
|
2018-03-09 13:15:30 +00:00
|
|
|
selectFields: '<?',
|
2018-04-04 13:03:13 +00:00
|
|
|
disabled: '<?',
|
2018-03-09 13:15:30 +00:00
|
|
|
where: '@?',
|
2017-10-18 10:51:33 +00:00
|
|
|
order: '@?',
|
2018-03-09 13:15:30 +00:00
|
|
|
label: '@',
|
|
|
|
initialData: '<?',
|
|
|
|
field: '=?',
|
|
|
|
limit: '<?',
|
|
|
|
showFilter: '<?',
|
|
|
|
selection: '<?',
|
|
|
|
multiple: '<?',
|
|
|
|
onChange: '&?'
|
2017-09-20 09:50:53 +00:00
|
|
|
},
|
|
|
|
transclude: {
|
|
|
|
tplItem: '?tplItem'
|
2018-03-09 13:15:30 +00:00
|
|
|
},
|
|
|
|
require: {
|
|
|
|
form: '?^form'
|
2017-09-13 12:59:58 +00:00
|
|
|
}
|
|
|
|
});
|