I noticed today that the array.js field type does not allow duplicates and also does not prevent the user from "adding" a new element once maxItemCount is reached. It does prevent you from "saving" the entity if maxItemCount is exceeded but I wanted to prevent user from even adding a new item once maxItemCount is reached.
In my case, I wanted this field to act like a true array where I don't specify any options in field definitions so that espo allows user to enter custom options.
After some trial and error, I have come up with the following code.
You will see that one needs to override some functions. I'm using espoCRM 8.0.6 at the moment. I hope it helps someone. This is what I have so far. Curious as to why duplicates would not be allowed in a field type "array" anyway..
In my case, I wanted this field to act like a true array where I don't specify any options in field definitions so that espo allows user to enter custom options.
After some trial and error, I have come up with the following code.
You will see that one needs to override some functions. I'm using espoCRM 8.0.6 at the moment. I hope it helps someone. This is what I have so far. Curious as to why duplicates would not be allowed in a field type "array" anyway..
Code:
define('custom:views/fields/custom-array.js, ['views/fields/array', 'helpers/reg-exp-pattern'], function(Dep, RegExpPattern) { return Dep.extend({ events: _.extend({ //overide removeValue action 'click [data-action="removeValue"]': function(e) { e.preventDefault(); e.stopPropagation(); let $listGroupItem = $(e.currentTarget).closest('div.list-group-item'); this.removeValue($listGroupItem); this.focusOnElement(); }, }), setup: function() { Dep.prototype.setup.call(this); // some initialization }, afterRender: function() { Dep.prototype.afterRender.call(this); // your customizations executed after the field is rendered }, //overide addValueFromUi addValueFromUi(value) { value = value.trim(); if (this.noEmptyString && value === '') { return; } if (this.params.pattern) { let helper = new RegExpPattern(this.getMetadata(), this.getLanguage()); let result = helper.validate(this.params.pattern, value, this.name, this.entityType); if (result) { setTimeout(() => this.showValidationMessage(result.message, 'input.select'), 10); return; } } // Do not allow adding more than maxItemLength if (this.params.maxCount && this.selected.length === (this.params.maxCount)) { let msg = this.translate('fieldExceedsMaxCount', 'messages') .replace('{field}', this.getLabelText()) .replace('{maxCount}', this.params.maxCount.toString()); this.showValidationMessage(msg, '.array-control-container'); return; } this.addValue(value); this.$select.val(''); this.controlAddItemButton(); }, //overide addValue addValue(value) { let html = this.getItemHtml(value); this.$list.append(html); this.selected.push(value); this.trigger('change'); }, //overide removeValue removeValue($listGroupItem) { let itemIndex = this.$list.children().index($listGroupItem); this.$list.children().eq(itemIndex).remove(); this.selected.splice(itemIndex, 1); this.trigger('change'); } }); });