Экспорт коллекции Backbone.js в Excel
Backbone.js

Экспорт коллекции Backbone.js в Excel

Нередко перед разработчиком встает задача экспорта данных в форматы XLS или CSV. Чаще всего эту задачу решают серверными средствами, а на клиент отдают уже готовый файл. Однако, с некоторыми ограничениями эта задача может быть решена исключительно на клиентской стороне.

В статье мы рассмотрим вариант генерации XLS файлов на клиенте в приложении на Backbone.js, а экспортировать будем данные коллекции.

Кнопки загрузки файлов

Для начала добавим кнопку для скачивания XLS файла в шаблон. На работе с шаблонами и представлениями здесь не будем заострять внимания, предположим у нас уже есть представление, где отображаются элементы коллекции:


<div class="table-tools-menu">
    <a class="export-xls">Скачать XLS</a>
</div>

Теперь в представление добавим обработчик события нажатия на эту кнопку:


events: {
    ...
    'click .table-tools-menu .export-xls': 'exportToXLS'
},

И наконец, добавим соответствующий метод обработчик:


exportToXLS: function(e) {
    return Backbone.ExportCollection.excel(
        $(e.currentTarget), 
        this.collection, 
        {
           title: 'Заголовок',
           author: 'Автор',
           pablisher: 'Издательство',
           year: 'Год издания'
        }
    );
}

В обработчике мы вызываем соответствующий метод excel объекта Backbone.ExportCollection. Метод exportToXLS принимает три параметра:

  • jQuery-объект кнопки, по которой произошло нажатие
  • коллекцию Backbone.js
  • список столбцов, которые будут экспортироваться.

Список столбцов представляет собой объект, где ключами являются названия атрибутов модели, которые будут экспортироваться, а значениями — текстовые заголовки этих атрибутов.

Backbone.ExportCollection

Всю подготовительную работу мы сделали, перейдем к реализации объекта Backbone.ExportCollection.

Прежде всего нам необходимо создать каркас модуля:


(function (name, definition) {
    if (typeof define === 'function') { // AMD
        define(definition);
    } else if (typeof module !== 'undefined' && module.exports) { // Node.js
        module.exports = definition();
    } else { // Browser
        var theModule = definition(), global = this;        
        global[name] = theModule;
    }
})('Backbone.ExportCollection', function() {
        
    Backbone.ExportCollection = (function() {
        
        // … приватные методы

        return {
            // публичные методы
            excel: function(collection, columns, name) {}
        };
    })();

    return Backbone.ExportCollection;
});

Мы получили модуль Backbone.ExportCollection с одним публичными методом excel.

Экспорт в Excel

Добавим реализацию экспорта коллекции в Excel.


excel: function($link, collection, columns) {
    var data = {
        worksheet: 'Worksheet',
        table: collectionToExcel(collection, columns)
    };

    return output({
        link: $link,
        data: format(template.excel, data),
        contentType: 'application/vnd.ms-excel',
        filename: 'export-collection.xls'
    });
}

Метод excel принимает, как мы уже говорили, jQuery-объект ссылки, коллекцию и список столбцов для экспорта. В методе мы формируем объект data, который имеет два свойства: worksheet — название листа таблицы и table — собственно таблица. В свою очередь таблица — это результат вызова метода collectionsToExcel. Реализуем этот метод:


var collectionToExcel = function(collection, columns) {
    var data = '<tr>';

    _.each(columns, function(column) {
        data = data + '<td><b>' + column + '</b></td>';
    });
    data = data + '</tr>';

    collection.each(function(model) {
        data = data + '<tr>';
        _.each(columns, function(column, columnName) {
            data = data + '<td>' + model.get(columnName) + '</td>';
        });
        data = data + '</tr>';
    });

    return data;
};

В методе collectionToExcel мы просто проходимся сначала по объекту со списком столбцов и формируем первую строку таблицы, а затем по моделям коллекции и формируем строки с данными.

Вернемся к рассмотреню метода excel. После того, как мы сформировали объект с данными — формируем и отдаем файл с помощью метода output. Этот метод принимает в качестве параметра объект со следующими свойствами:

  • link — jQuery-объект ссылки, по которой произошло нажатие;
  • data — данные;
  • contentType — ContentType результирующего файла;
  • filename — имя файла для скачивания.

Мы еще рассмотрим этот метод подробнее. А пока обратите внимание, что ему мы передаем не сырые данные, а отформатированные с помощью функции format(template.excel, data), которой передаем шаблон и данные. Эту функцию также стоит добавить в приватные методы объекта Backbone.ExportCollection:


var template = {
    excel: '{table}
' }; var format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }); };

В функции format нет ничего сложного — она берет свой первый параметр в качестве определенного шаблон, заменяет переменные шаблона значениями свойств второго параметра и возвращает полученный результат.

Скачивание результирующего XLS-файла

Снова вернемся к методу excel. После того, как мы сформировали объект с данными, мы возвращает результирующий файл с помощью функции output. Добавим реализацию этой функции в приватные методы объекта Backbone.ExportCollection:


var output = function(params) {
    var blob, url;
            
    if (navigator.userAgent.toLowerCase().indexOf('safari/') > -1
       || navigator.userAgent.toLowerCase().indexOf('opera/') > -1) {
        url = window.location.protocol + '//' + window.location.host + '/download.php';
        $('body').append($('<form id="download" method="post" action="' + url + '" "><input type="hidden" name="filename" value="' + params.filename + '"/><input type="hidden" name="data" value="' + btoa(params.data) + '"/><input type="hidden" name="content_type" value="' + params.contentType + '"/></form>'));
        $('#download').submit().remove();
        return false;
    }
            
    if (typeof window.URL !== 'undefined' && typeof window.URL.createObjectURL !== 'undefined') {
        blob = new Blob([params.data], { type: params.contentType }),
        url = window.URL.createObjectURL(blob);

        params.link.attr({
            download: params.filename,
            href: url
        });
        return true;
    }
};

Для скачивания результирующего файла мы использовали атрибут download ссылки. Как раз для этого мы и передавали кнопку, по которой произошло нажатие в метод excel. В функции output мы мы формируем объект данных с помощью объекта Blob, создаем его URL с помощью window.URL и устанавливаем в качестве атрибута href ссылки. Для того, чтобы файл скачивался с нужным нам именем и расширением, мы также задаем значение атрибута download ссылки.

Указанный способ корректно работает в Firefox и Chrome, однако не поддерживается браузерами Opera и Safari. Именно это и относится к ограничениям, которые упоминались в начале статьи.

Однако для этих браузеров мы реализовали небольшой хак, все же использующий серверный код. Мы добавляем в body форму, полями которой являются имя файла, contentType и собственно данные, сабмитим ее и сразу удаляем. Серверный скрипт, получающий данную форму, формирует файл, устанавливает необходимые заголовки и отдает файл.

Заключение

В статье мы рассмотрели способ реализации экспорта коллекции Backbone.js в Excel на клиенте. Стоит заметить, что Backbone.js в данном случае был выбран исключительно для примера. Такой способ подойдет для экспорта совершенно любых данных.

Рассылка
Подпишитесь на рассылку и получайте дайджест новостей и статей.
Никакого спама!
Подписаться