Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   AngularJS и плагин jQuery UI (https://javascript.ru/forum/angular/50630-angularjs-i-plagin-jquery-ui.html)

Sufir 05.10.2014 10:41

AngularJS и плагин jQuery UI
 
В общем, есть на странице селект, по которому фильтруется вывод основных данных. Он должен быть декорирован Selectmenu.
Я набросал простейшую директиву:
function($scope, element, attrs, controller) {

        // Получаю опции из атрибута
        var options = $scope.$eval(attrs['selector']);

        angular.extend(options, {
            // Без этого модель привязанная к селекту не обновляется
            change: function(event, object) {
                element.trigger('change');
            }
        });

        // Применяю плагин
        $(element).selectmenu(options);

}


Тут всё хорошо, всё работает. Но т.к. приложение RESTfull (это мой первый опыт) данные для селекта должны подгружаться динамически. И в итоге получается, что когда данные пришли и оригинальный селект заполнился - Selectmenu уже применён и пустой.
Причём получается от случая к случаю: обновляешь страницу, если данные пришли быстро - то и в декорированном селекте появились, если нет то он пустой (оригинальный, который скрыт в порядке).

Я пробовал вызывать .selectmenu("refresh"); после загрузки данных:
$scope.staffList = Staff.query({fOnlyAuthors: 1}, function(){
        // console.log(jQuery(".selector", element).length)
        jQuery(".selector", element).selectmenu("refresh");
});

Но это эффекта не имеет, селект по прежнему остаётся пустым.

Подскажите как правильно решить данный вопрос?
Как-то организовать отложенное применение декорирующей директивы или обновление плагина?

melky 05.10.2014 12:18

можно демку на plunker ?

nerv_ 05.10.2014 13:31

делай по аналогии
/*
 ОБертка для jquery-chosen
 */
.directive('ngChosen', function() {
    return {
        replace: true,
        link: function(scope, element, attributes) {
            var params = scope.$eval(attributes.ngChosen) || {};

            element.chosen(params);

            function handler() {
                element.trigger('chosen:updated');
            }

            element.bind('$destroy', scope.$watch(attributes.ngModel, handler));
            element.bind('$destroy', scope.$watch(attributes.ngDisabled, handler));
        }
    };
})

Sufir 06.10.2014 11:13

Цитата:

Сообщение от nerv_ (Сообщение 333535)
делай по аналогии
/*
 ОБертка для jquery-chosen
 */
.directive('ngChosen', function() {
    return {
        replace: true,
        link: function(scope, element, attributes) {
            /.../
        }
    };
})

Такой вариант так же не имеет эффекта, список почему-то ни в какую не обновляется. Хотя обработчик успешно запускается.

Что самое интересное, получается, если не трогать селект до того момента как получены данные - список формируется. Специально для проверки ставил таймаут, что б подольше получать данные, и до трёх-четырёх секунд грузятся, но появляются. А если сразу после загрузки страницы по декорированному селекту кликнуть, то он так и остаётся пустым в дальнейшем.

// UPD: //
Извиняюсь, тупанул, не тот триггер вызывал. Да, действительно сработало! Но мне не совсем понятно. Мы биндим триггер обновляющий список на событие $destroy. Почему именно на него? Что-то посмотрел в документацию, и не понял.
Не могли бы вы вкратце объяснить, что происходит в данной ситуации?

Sufir 06.10.2014 12:28

Ан, нет, снова я поспешил. Всё равно через раз работает. Поясните, пожалуйста, что нужно сделать, возможно я смогу подпилить?

По всей вероятности не вызывается событие когда надо. Если модель меняется уже после загрузки данных, до да, всё происходит как нужно. Но после первоначальной загрузки страницы список пуст.

Sufir 06.10.2014 14:00

$scope.staffList = Staff.query({fOnlyAuthors: 1}, function(){
        jQuery(".selector", element).selectmenu("destroy").selectmenu();
});

Вот так работает, т.е. директиву можно убрать вообще. Но вероятно это не правильно. Вообще не понятно почему в этом месте срабатывают корректно любые методы плагина (destroy, disable, open) только не refresh.

nerv_ 06.10.2014 16:21

html
<select ng-model="app.model.property" ng-options="item.id as item.title for item in app.dictionaries.categories" ng-chosen=""></select>


js
/**
 * jQuery-chosen wrapper
 * @see [url]http://harvesthq.github.io/chosen/[/url]
 */
.directive('ngChosen', [
    function() {
        return {
            link: function(scope, element, attributes) {
                var options = scope.$eval(attributes.ngChosen);
                var settings = angular.extend({}, options);
    
                element.chosen(settings);
    
                element.bind('$destroy', scope.$watch(attributes.ngModel, handler));
                element.bind('$destroy', scope.$watch(attributes.ngDisabled, handler));
                element.bind('$destroy', destructor);
    
                // -----------------------
    
                function handler() {
                    element.trigger('chosen:updated');
                }
    
                function destructor() {
                    element.chosen('destroy');
                }
            }
        };
    }
])

Sufir 07.10.2014 12:02

Мой окончательный вариант:
directive('selector', function() {
    return {
        restrict: 'A',
        replace: true,
        //require: '?ngModel',
        link: function($scope, element, attributes, controller) {

            var options = $scope.$eval(attributes['selector']) || {};

            angular.extend(options, {
                change: function(event, object) {
                    element.trigger('change');
                }
            });

            element.selectmenu(options);

            element.bind('$destroy', $scope.$watch(attributes.ngModel, handler));
            element.bind('$destroy', $scope.$watch(attributes.ngDisabled, handler));
            element.bind('refresh-me', refreshMe);

            function handler() {
                element.selectmenu("refresh");
            }

            function refreshMe() {
                element
                    .selectmenu("destroy")
                    .selectmenu(options);
            }

        }
    };
});

<select class="selector"
     ng-model="selectedStaff"
     ng-options="(staff.surname + ' ' + staff.name) for staff in staffList"
     data-selector="{icons: {button: 'ui-icon-list'}}">

$scope.staffList = Staff.query({}, function(){
    $(".selector", element).trigger('refresh-me');
}


Не уверен, что в полной мере правильно с точки зрения Angular, но задачу решает.
nerv_, спасибо за помощь и наводки.


Часовой пояс GMT +3, время: 19:24.