AngularJS adaptation of ui-select for x-editable with the additional ability to add objects on the fly

    Hello!

    Recently I happened to adapt ui-select to x-editable in Angular and since I had to spend a certain amount of time collecting bit by bit the most acceptable option, today I decided to share my best practices with you, in the hope that it will save someone time.

    In short, the resulting directive replaces the standard editable-select, plus the additional ability to add objects on the fly.

    Now in more detail.

    To start, I’ll start from the end and give the code for a directive that allows you to add a button to ui-select. A function is hung on this button, in my case, a function that calls a modal window (ui-bootstrap modal) with the form of adding a new object:
    app.directive("addNewItem", function($timeout) {
        return {
            restrict: "A",
            link: function(scope, e, attrs) {
                var method = attrs.addNewItem;
                var template = "
    "+ ""+ "
    "; 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(); } }); } } })


    In principle, the code is extremely simple, so I will focus on a couple of points. Firstly, ui-select does not close after clicking a button, but closes if you click somewhere on the modal window. Therefore, I had to add a crutch with $ timeout.
    Secondly (regarding the last if else): if no elements are found in the ui-select search, I pass the search value to the method in order to autofill the form with this value in the future and thus save a little time.

    Now the main directive:

    app.directive('editableUiSelect', 
            ['editableDirectiveFactory', 'editableNgOptionsParser', 
            function(editableDirectiveFactory, editableNgOptionsParser) {
                var dir = editableDirectiveFactory({
                    directiveName: 'editableUiSelect',
                    inputTpl: '',
                    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 = ""+
                                   "" +
                                   "";
                        this.inputEl.removeAttr('ng-options');
                        this.inputEl.append(html);
                    }
                });
                return dir;
            }]);
    


    The directive was made in the image of the standard xeditable directives, and then slightly redone.
    One of the main problems that I encountered when writing the directive was the inability to change the model, so an additional method for on-select was added.

    You can use all this like this:

    
        {{ entity.property.name }}
    


    And finally, a bonus. If you use this thing in table-responsive (bootstrap), then the drop-down list can be overridden by the table (especially if it consists of a couple of rows). You can fix this by adding css:

    .table-responsive .ui-select-dropdown {
        position: relative !important;
    }
    


    Conclusion . There may be many options for implementing this directive, and there are probably better options among them. I published my work only because the official xeditable documentation does not yet mention ui-select support, and also because I found little information on the topic, and the one that I found differs.

    I hope that the guru of the angular will help me improve my directive, as well as the fact that this article is useful to someone.

    UPD . A small example: plnkr.co/edit/5dPKCnzbKE8D9XIR8ocX?p=preview

    Also popular now: