- PVSM.RU - https://www.pvsm.ru -
Давно писал модуль для загрузки файлов и всё он был не идеальным. И тут подумал, если сейчас не опубликую, то никогда не опубликую, идеал-то не достижим!
При составлении АПИ руководствовался принципом — как можно проще. Поэтому сначала несколько мыслей о загрузке файлов:
Загрузка только методом POST. Как показала практика, сам по себе файл почти никогда не бывает отдельной сущностью и всегда привязан к каким-то другим данным в базе, поэтому создавать запись вместе с загрузкой файла — плохая идея. Правильно: сначала создать запись, потом отдельным запросом добавить туда файл. Такой подход снимает кучу вопросов, связанных с отменой загрузки, параллельным редактированием описания файла и проч. Так же, создавая запись предварительно, мы можем получить в ответ данные о количестве свободного места на сервере и использовать их для валидации на клиенте.
Загрузка каждого файла отдельным запросом. На любом
Никаких отложенных загрузок. Файл должен загружаться сразу после добавления (не в 2000 году, чай, живем), поэтому никаких методов работы с очередью — выбрал файл, выбрал еще 5 штук, удалил один, нажал «отправить» — не будет. Зато будет отмена загрузки.
Не стоит разделять загрузку файлов по кнопке и перетаскиванием. В моем случае любая область, помеченная директивой позволяет перетаскивать на нее файлы, а если это инпут с типом file, то еще и в проводнике можно выбрать. Очень удобно знать, что на кнопку можно перетаскивать, когда потянул в браузер 10 файлов, а дизайнер забыл подсветить поле перетаскивания, и гадаешь перетащатся ли они или откроются в новом окне.
Так же, идеальным, был бы вариант загрузки через метод $save ресурса или подобный, но такого расширения можно долго ждать от разработчиков (костыль на эту тему [2]). Пока так глубоко не влезал, поэтому сделал чуть более топорно.
Подключение модуля:
angular.module('myApp', ['oi.file']);
Использование директивы в HTML-шаблоне:
<!-- Загрузка через проводник и перетаскиванием -->
<input type="file" oi-file="options">
<!-- Загрузка перетаскиванием на область -->
<ul oi-file="options">
<li ng-repeat="item in items">
<img ng-src="{{item.thumb}}">
</li>
</ul>
Настройка в контроллере:
$scope.file = {} //Модель
$scope.options = {
//Вызывается для каждого выбранного файла
change: function (file) {
//В file содержится информация о файле
//Загружаем на сервер
file.$upload('uploader.php', $scope.file)
})
}
}
Создание элемента модели для каждого файла:
$scope.items = model;
$scope.options = {
change: function (file) {
//Создаем пустой элемент для будущего файла
$scope.add(function (i, id) {
//Загружаем картинку через FileReader до загрузки на сервер
file.$preview($scope.items[i]);
//Загружаем на сервер
file.$upload('uploader.php' + id, $scope.items[i], {allowedType: ["jpeg", "jpg", "png"]})
.catch(function (data) {
//Удаляем элемент при неудачной загрузке
$scope.del(data.item.id);
})
})
}
}
Метод catch
доступен, начиная с Ангуляра 1.2. В старых версиях используйте вместо него then(null, function (data) {...})
. $preview
и $upload
возвращают обещания. См. $q [3].
Пример с уменьшением изображения на клиенте:
file.$preview({})
.then(function (data) {
//Изображение прочитано. Уменьшаем его с помощью canvas
minimize(file._file);
//Отправляем
file.$upload('uploader.php', $scope.avatar)
}, function (data) {
//Изображение не прочитано. Отправляем как есть
file.$upload('uploader.php', $scope.avatar)
});
Гитхаб [4], демонстрация [5], песочница [6]
Параллельно nervgh [7] написал angular-file-upload [8] с гораздо более богатым АПИ, где на каждый чих формируется событие. Обратите внимание, кого не устроит бедность моего.
Автор: tamtakoe
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/41808
Ссылки в тексте:
[1] хостинге: https://www.reg.ru/?rlink=reflink-717
[2] костыль на эту тему: https://github.com/uor/angular-file
[3] $q: http://www.angular.ru/api/ng.%24q
[4] Гитхаб: https://github.com/tamtakoe/oi.file
[5] демонстрация: http://tamtakoe.ru/uploader/
[6] песочница: http://plnkr.co/edit/HKbvgle4zqfqCKcpLJDi?p=preview
[7] nervgh: http://habrahabr.ru/users/nervgh/
[8] angular-file-upload: https://github.com/nervgh/angular-file-upload
[9] Источник: http://habrahabr.ru/post/191464/
Нажмите здесь для печати.