Здравствуйте!
Недавно мне довелось адаптировать ui-select под x-editable в Ангуляре и поскольку для этого пришлось потратить определенное количество времени, собирая по крупицам наиболее приемлемый вариант, сегодня я решил поделиться своими наработками с вами, в надежде на то, что кому-нибудь это сэкономит время.
Если вкратце, то полученная в итоге директива замещает стандартный editable-select, плюс дополнительная возможность добавлять объекты на лету.
Теперь подробнее.
Для начала начну с конца и приведу код директивы, позволяющей добавить кнопку в ui-select. На эту кнопку вешается функция, в моем случае — функция, вызывающая модальное окно(ui-bootstrap modal) с формой добавления нового объекта:
app.directive("addNewItem", function($timeout) { return { restrict: "A", link: function(scope, e, attrs) { var method = attrs.addNewItem; var template = "<div class='add-new-item-container'>"+ "<button class='btn btn-xs btn-default pull-right'>Добавить</button>"+ "<div class='clearfix'></div></div>"; e.find('li.ui-select-choices-group').append(template); e.find('div.add-new-item-container button').bind('click', function() { // workaround for closing ui-select $timeout(function() { e.trigger("click"); }); var searchResult = e.find('li.ui-select-choices-row').length; if ( ! searchResult ) { var value = e.find('input.ui-select-search').val(); scope[method].apply(null, [value]); } else { scope[method].apply(); } }); } } })
В принципе, код предельно прост, поэтому остановлюсь на паре моментов. Во-первых, ui-select не закрывается после нажатия кнопки, но закрывается, если кликнуть куда-нибудь по модальному окну. Поэтому пришлось добавить костыль с $timeout.
Во-вторых, (по поводу последнего if else): если в поиске ui-select не найдено ни одного элемента, я передаю значение поиска в метод, чтобы в дальнейшем автозаполнить этим значением форму и таким образом немного сэкономить время.
Теперь основная директива:
app.directive('editableUiSelect', ['editableDirectiveFactory', 'editableNgOptionsParser', function(editableDirectiveFactory, editableNgOptionsParser) { var dir = editableDirectiveFactory({ directiveName: 'editableUiSelect', inputTpl: '<ui-select></ui-select>', render: function() { this.parent.render.call(this); var parsed = editableNgOptionsParser(this.attrs.eNgOptions); this.inputEl.attr('ng-model', 'editable.entity'); // слева директива, описанная вначале, // справа - метод, в моем случае вызывающий модальное окно с формой добавления this.inputEl.attr('add-new-item', 'addNewItem'); // поскольку модель самостоятельно не меняется, пришлось добавить этот метод this.inputEl.attr('on-select', 'setModel($item)'); this.inputEl.attr('theme', 'select2'); this.inputEl.css('width', '200px'); var html = "<ui-select-match><span ng-bind='$select.selected.name'></span></ui-select-match>"+ "<ui-select-choices repeat='" + parsed.ngRepeat + "'>" + "<span ng-bind-html='" + parsed.locals.displayFn + "'></span></ui-select-choices>"; this.inputEl.removeAttr('ng-options'); this.inputEl.append(html); } }); return dir; }]);
Директива была сделана по образу и подобию стандартных директив xeditable, а потом немного переделана.
Одной из основных проблем, с которыми я столкнулся при написании директивы, была невозможность изменить модель, поэтому был добавлен дополнительный метод для on-select.
Использовать все это можно так:
<span data-pk="{{ entity.id }}" editable-ui-select="entity.property" ng-model="entity.property" e-ng-options="obj.id as obj.name for obj in objects | filter: $select.search track by obj.id" e-form="rowform"> {{ entity.property.name }} </span>
И напоследок бонус. Если использовать это дело в table-responsive (bootstrap), то выпадающий список может быть перекрыт таблицей (особенно, если она состоит из пары строк). Исправить это можно, добавив css:
.table-responsive .ui-select-dropdown { position: relative !important; }
Заключение. Вариантов реализации данной директивы может быть множество и наверняка среди них есть варианты лучше моего. Я опубликовал свои наработки только потому, что в официальной документации xeditable пока нету упоминания о поддержке ui-select, а также потому, что я нашел мало информации по теме, а та, что нашел, разнится между собой.
Надеюсь на то, что гуру ангуляра помогут мне улучшить мою директиву, а также на то, что кому-нибудь пригодится эта статья.
ссылка на оригинал статьи https://habrahabr.ru/post/277001/
Добавить комментарий