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");
});
Но это эффекта не имеет, селект по прежнему остаётся пустым. Подскажите как правильно решить данный вопрос? Как-то организовать отложенное применение декорирующей директивы или обновление плагина? |
можно демку на plunker ?
|
делай по аналогии
/*
ОБертка для 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));
}
};
})
|
Цитата:
Что самое интересное, получается, если не трогать селект до того момента как получены данные - список формируется. Специально для проверки ставил таймаут, что б подольше получать данные, и до трёх-четырёх секунд грузятся, но появляются. А если сразу после загрузки страницы по декорированному селекту кликнуть, то он так и остаётся пустым в дальнейшем. // UPD: // Извиняюсь, тупанул, не тот триггер вызывал. Да, действительно сработало! Но мне не совсем понятно. Мы биндим триггер обновляющий список на событие $destroy. Почему именно на него? Что-то посмотрел в документацию, и не понял. Не могли бы вы вкратце объяснить, что происходит в данной ситуации? |
Ан, нет, снова я поспешил. Всё равно через раз работает. Поясните, пожалуйста, что нужно сделать, возможно я смогу подпилить?
По всей вероятности не вызывается событие когда надо. Если модель меняется уже после загрузки данных, до да, всё происходит как нужно. Но после первоначальной загрузки страницы список пуст. |
$scope.staffList = Staff.query({fOnlyAuthors: 1}, function(){
jQuery(".selector", element).selectmenu("destroy").selectmenu();
});
Вот так работает, т.е. директиву можно убрать вообще. Но вероятно это не правильно. Вообще не понятно почему в этом месте срабатывают корректно любые методы плагина (destroy, disable, open) только не refresh. |
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');
}
}
};
}
])
|
Мой окончательный вариант:
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, время: 13:05. |