X-editable и Select2

x-editable select2Хочу рассказать о своих мытарствах при использовании библиотеки x-editable совместно с select2 для редактирования данных в таблице dataTablesЧасть вторая

Дано: данные демонстрируются на странице посредством dataTables и нужно прямо в таблице, не переходя к отдельным записям редактировать изменчивые данные.
К примеру в таблице задач надо выбрать или поменять исполнителя для этой задачи и редактировать некоторые числовые факторы, которые нужны для выполнения и контроля выполнения задачи.
Screenshot_1Выводим данные в таблицу и прицепляем свежие версии библиотек x-editable и select2.
По мануалу вешаем редактирование на числовые данные.

''+id+''
$('.dataTable a.x-edit-number').editable({
    url : '/tasks/edit-field/',
    type : 'text',
    inputclass : 'input-small form-control',
    defaultValue : '0',
    validate: function(value) {
        if($.trim(value) > '' && parseInt(value) != value) {
            return 'Введите целое число';
        }
    }
});

Отлично запустилось сразу же. По клику всплывает поле для редактирования, можно изменить и сохранить, есть возможность отменить редактирование.
Не все так радужно оказалось с выбором из списка.
Подгружать данные для списка при загрузке страницы, на случай если пригодится для редактирования — довольно глупо. Совершенно не нужна нам дополнительная нагрузка на сервер.
Подгружать исполнителей правильно будет — только в случае необходимости, когда уже кликнули на ячейку таблицы, непосредственно перед открытием плашки редактирования.
Эти данные не должны загружаться повторно при выборе исполнителей для других задач. Возможных исполнителей у нас под 50, поэтому select должен быть с поиском. На этом этапе анализа требований — просто select отвалился, самый подходящий вариант — select2.
Вот тут-то и началось самое интересное.
Screenshot_6
Пробуем запустить — код подобный вышеприведенному, только type : ‘select2’ и задаем source : ‘/users/automoplete/empls/’ — по этому адресу сайт отдает json массив со списком исполнителей, каждый элемент массива представляет собой object вида {id:’99’, text:’Имя исполнителя’}.
Screenshot_2
Щелкаем на стрелочку открытия select-элемента — происходит подгрузка списка исполнителей. Поле поиска присутствует, все исполнители на месте — доступны для выбора.
Но один взгляд в консоль разработчика — обозначил проблему — каждое открытие списка в плашке редактирования предваряется запросом на сервер для очередного получения списка всех исполнителей. В каждый запрос подставляется get параметр ?query=.
Пробуем включить кеширование — добавляем в конфигурацию editable секцию select2

$('.dataTable a.x-edit-select2').editable({
    ...
    select2 : {
        cache : true,
        minimumResultsForSearch : 7,
        placeholder : 'Выберите исполнителя',
        allowClear : true
    }
});

Полный вариант инициализации опубликую, после того, как будет готов окончательный вариант.

Не помогло — постоянные запросы на сервер при каждом телодвижении.
Ну что ж — придется позаботиться о кешировании самому.
То есть при клике на ячейку нам не надо, чтобы сразу открывалась плашка редактирования, сначала мы подгружаем список исполнителей, засовываем его в source и только потом показываем плашку.

$('.dataTable a.x-edit-select2').click(function() {
    // инициализацию и вызов плашки 
    // редактирования лучше вынести 
    // в отдельную функцию, чтобы не дублировать код
    // для инициализации в случаях, когда список
    // запрашивается и когда уже закеширован
    function showEditForm(data) {
        // инициализируем editable только 
        // один раз для ячейки
        if (!cell.data('source-setted')) {
            cell.editable({
                url : '/tasks/edit-field/',
                type : 'select2',
                inputclass : 'form-control input-medium',
                toggle : 'manual',
                source : data,
                emptytext : '',
                select2 : {
                    minimumResultsForSearch : 7,
                    placeholder : 'Выберите исполнителя',
                    allowClear : true
                }
            });
            cell.data('source-setted', true);
        }
        cell.editable('show');
    }
    var cell = $(this);
    // чтобы не загаживать глобальное пространство имен, 
    // все свое пакуем в объект App
    // проверяем объявлен ли он уже
    if (typeof App == 'undefined') var App = {};
    if (typeof App.cache == 'undefined') App.cache = {};
    // если списка еще нет
    if (typeof App.cache.empls == 'undefined') {
        cell.addClass('loading');
        url = '/users/autocomplete/empls/';
        $.post(
            url, {},
            function(answ) {
                cell.removeClass('loading');
                answ = App.parseJSON(answ);
                if (answ !== false) App.cache.empls = answ;
                showEditForm(App.cache.empls);
            },
            'text'
        );
    // список уже получен, надо только инициализировать
    // (если необходимо)
    // и открыть плашку редактирования
    } else {
        showEditForm(App.cache.empls);
    }
    return false;
});

Работает! Запрос на сервер только один, поиск отрабатывает как положено, повторных запросов на сервер не производится.
Но остается еще несколько неприятных моментов, которые надо устранить, чтобы было действительно удобно для использования.
О них в следующей части →.