import ngModule from '../../module'; import Input from '../../lib/input'; import './style.scss'; /** * 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 */ export default class Autocomplete extends Input { constructor($element, $scope, $http, $transclude) { super($element, $scope); this.$http = $http; this.$transclude = $transclude; this._field = undefined; this._selection = null; this.valueField = 'id'; this.showField = 'name'; this._multiField = []; this.readonly = true; this.form = null; this.input = this.element.querySelector('.mdl-textfield__input'); componentHandler.upgradeElement( this.element.querySelector('.mdl-textfield')); } /** * @type {any} The autocomplete value. */ get field() { return this._field; } set field(value) { if (angular.equals(value, this._field)) return; this._field = value; this.refreshSelection(); if (this.onChange) this.onChange({value}); } /** * @type {Object} The selected data object, you can use this property * to prevent requests to display the initial value. */ get selection() { return this._selection; } set selection(value) { this._selection = value; this.refreshDisplayed(); } selectionIsValid(selection) { return selection && selection[this.valueField] == this._field && selection[this.showField] != null; } refreshSelection() { if (this.selectionIsValid(this._selection)) return; let value = this._field; if (value && this.valueField && this.showField) { if (this.selectionIsValid(this.initialData)) { this.selection = this.initialData; return; } let data = this.data; if (!data && this.$.dropDown) data = this.$.dropDown.$.model.data; if (data) for (let i = 0; i < data.length; i++) if (data[i][this.valueField] === value) { this.selection = data[i]; return; } if (this.url) { this.requestSelection(value); return; } } else this.selection = null; } requestSelection(value) { let where = {}; if (this.multiple) where[this.valueField] = {inq: this.field}; else where[this.valueField] = value; let filter = { fields: this.getFields(), where: where }; let json = encodeURIComponent(JSON.stringify(filter)); this.$http.get(`${this.url}?filter=${json}`).then( json => this.onSelectionRequest(json.data), () => this.onSelectionRequest(null) ); } onSelectionRequest(data) { if (data && data.length > 0) { if (this.multiple) this.selection = data; else this.selection = data[0]; } else this.selection = null; } 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(); } getFields() { let fields = []; fields.push(this.valueField); fields.push(this.showField); if (this.selectFields) for (let field of this.selectFields) fields.push(field); return fields; } mdlUpdate() { let field = this.element.querySelector('.mdl-textfield'); let mdlField = field.MaterialTextfield; if (mdlField) mdlField.updateClasses_(); } setValue(value) { this.field = value; if (this.form) this.form.$setDirty(); } onDropDownSelect(value) { this.setValue(value); this.field = value; } onClearClick(event) { event.preventDefault(); this.setValue(null); } onKeyDown(event) { if (event.defaultPrevented) return; 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; } event.preventDefault(); } onMouseDown(event) { event.preventDefault(); this.showDropDown(); } showDropDown(search) { Object.assign(this.$.dropDown.$.model, { url: this.url, staticData: this.data }); Object.assign(this.$.dropDown, { valueField: this.valueField, showField: this.showField, selectFields: this.getFields(), where: this.where, order: this.order, parent: this.input, multiple: this.multiple, limit: this.limit, $transclude: this.$transclude }); this.$.dropDown.show(search); } } Autocomplete.$inject = ['$element', '$scope', '$http', '$transclude']; ngModule.component('vnAutocomplete', { template: require('./autocomplete.html'), controller: Autocomplete, bindings: { url: '@?', data: '