File attachments

The file attachments module contains two directives to add files to forms and display summary information about attachments.

The bb-file-drop directive provides an element that users can click to select files from their local drives or use as a drop zone to drag and drop files. The directive can also display controls for users to provide hyperlinks to files on the web. You can leave the contents of the directive blank to display the drop zone's default UI, or you can specify custom content to display instead.

When the SKY UX module initializes, it disables the ability to drag and drop files for the entire window. This prevents the browser from opening files that are accidentally dropped outside the target zone. If you implement your own file drop functionality outside of the file drop directive, you can place the bb-file-drop-target CSS class on the element that receives drop events to exempt it from the drop exclusion rule.

The bb-file-item directive displays summary information about files that users attach to forms. By default, the directive displays file names, delete buttons, and fields for names and tags.. For files from local drives, the directive also displays file sizes and thumbnails.

File drop settings

  • bb-file-drop — Provides an element for users to click to select files from local drives or to use as a drop zone to drag and drop files.
    • bb-file-drop-accept(Optional.) Provides a comma-delimited string literal of MIME types that users can drop or select (bb-file-drop-accept="fileAttachmentDemo.validFileTypes" or bb-file-drop-accept="'image/png'"). By default, any type of file is allowed.
    • bb-file-drop-multiple(Optional.) Indicates whether users can drag and drop multiple files at the same time. (Default: true)
    • bb-file-drop-allow-dir(Optional.) Indicates whether users can select a directory when they attach files. (Default: true)
    • bb-file-drop-min-size(Optional.) Specifies the minimum size in bytes for valid files.
    • bb-file-drop-max-size(Optional.) Specifies the maximum size in bytes for valid files.
    • bb-file-drop-change — Specifies a function to be called when users attach files. The function accepts two parameters:
      • files — An array of valid files that a user attaches. Each item is a JavaScript File object.
      • rejectedFiles — An array of invalid files that do not meet file type or size requirements.
    • bb-file-drop-link(Optional.) Indicates whether to display an option for users to provide hyperlinks to files on the web. To display this hyperlink option, you include this attribute with no value.
    • bb-file-drop-link-change(Optional.) Specifies a function to be called when users add hyperlinks. The function accepts a link parameter with a url property that contains the hyperlink.
    • bb-file-drop-noclick(Optional.) Disables the option for users to click the element and select files through a file dialog. To disable the option, you include this attribute with no value.
    • bb-file-drop-validate-fn(Optional.) Provides a custom validation function (bb-file-drop-validate-fn="fileAttachmentDemo.validate($file)"). By default, any type of file is allowed.

File item settings

  • bb-file-item — Displays summary information about files that users attach to forms. By default, the directive displays file names, delete buttons, and fields for names and tags. For files from local drives, it also displays file sizes and thumbnails.
  • bb-file-item-delete — Specifies a function to be called when users click the delete button for an item. The deleted item is passed to the function.

File single settings

  • bb-file-single — Provides an element for users to click to select a single file from local drives or to use as a drop zone to drag and drop a file.
    • bb-file-single-item — Specifies a JavaScript File object that will be bound as the single item. If there is no initial file, users will be prompted to choose a file.
    • bb-file-single-accept(Optional.) Provides a comma-delimited string literal of MIME types that users can drop or select (bb-file-single-accept="fileAttachmentDemo.validFileTypes" or bb-file-single-accept="'image/png'"). By default, any type of file is allowed.
    • bb-file-single-min-size(Optional.) Specifies the minimum size in bytes for a valid file.
    • bb-file-single-max-size(Optional.) Specifies the maximum size in bytes for a valid file.
    • bb-file-single-change(Optional.) Specifies a function to be called when users attach a file. The function accepts two parameters:
      • file — A single valid file that a user attaches. The item is a JavaScript File object.
      • rejectedFiles — An array of invalid files that do not meet file type or size requirements.
    • bb-file-single-link-action(Optional.) Indicates whether to allow users to click the name of the file to perform a given action.
    • bb-file-single-validate-fn(Optional.) Provides a custom validation function (bb-file-single-validate-fn="fileAttachmentDemo.validate($file)"). By default, any type of file is allowed.
    • bb-file-single-remove(Optional.) Specifies a function to be called when users click the remove button for the item. The removed item is passed to the function.
    • bb-file-single-id(Optional.) Specifies the id attribute to place onto the internal input element. The name attribute is set to the same value.

Demo

The file {{fileAttachmentDemo.rejected[fileAttachmentDemo.rejected.length - 1].name}} is invalid. {{fileAttachmentDemo.rejected[fileAttachmentDemo.rejected.length - 1].$errorParam}}

Markup

<div ng-controller="FileAttachmentDemoController as fileAttachmentDemo">
    <div class="row">
        <div class="col-md-6">
            <div
                 bb-file-drop
                 bb-file-drop-change="fileAttachmentDemo.fileDropped(files, rejectedFiles)"
                 bb-file-drop-multiple="true"
                 bb-file-drop-max-size="5000000"
                 bb-file-drop-link
                 bb-file-drop-link-change="fileAttachmentDemo.fileLinked(link)"
                 bb-file-drop-validate-fn="fileAttachmentDemo.fileValidate(file)">
            </div>
            <bb-alert bb-alert-type="danger" bb-alert-closeable="true" bb-alert-closed="fileAttachmentDemo.alertClosed" ng-if="fileAttachmentDemo.rejected.length > 0">
              The file <strong>{{fileAttachmentDemo.rejected[fileAttachmentDemo.rejected.length - 1].name}}</strong> is invalid.  
              {{fileAttachmentDemo.rejected[fileAttachmentDemo.rejected.length - 1].$errorParam}}
            </bb-alert>
            <div ng-repeat="item in fileAttachmentDemo.allItems" bb-file-item="item" bb-file-item-delete="fileAttachmentDemo.deleteAttachment(item)" style="margin-bottom: 10px">
                <div class="form-group">
                    <label for="filename-{{$index}}" >Name for this attachment</label>
                    <input id="filename-{{$index}}" type="text" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="filetag-{{$index}}">Tags for this attachment</label>
                    <input id="filetag-{{$index}}" type="text" class="form-control" />
                </div>
            </div>
            <form name="singleFileForm">
                <label for="singleFileId" class="required">Single File Label</label>
                <div 
                    bb-file-single
                    bb-file-single-max-size="5000000"
                    bb-file-single-required="true"
                    bb-file-single-accept="'image/png'"
                    bb-file-single-change="fileAttachmentDemo.fileChange(file, rejectedFiles)"
                    bb-file-single-validate-fn="fileAttachmentDemo.fileValidate(file)" 
                    bb-file-single-link-action="fileAttachmentDemo.fileLinkAction()"
                    bb-file-single-item="fileAttachmentDemo.singleFile"
                    bb-file-single-id="singleFileId">
                </div>
            </form>
        </div>
    </div>
</div>

JavaScript

/*global angular */
(function () {
    'use strict';

    function FileAttachmentDemoController($scope) {
        var vm = this;

        function removeFromArray(items, obj) {
            var i,
                n;

            if (items) {
                for (i = 0, n = items.length; i < n; i++) {
                    if (items[i] === obj) {
                        items.splice(i, 1);
                        break;
                    }
                }
            }
        }

        vm.attachments = [];
        vm.links = [];
        vm.rejected = [];
        vm.allItems = [];
        vm.singleFile = null;

        vm.fileDropped = function (files, rejectedFiles) {
            vm.attachments = vm.attachments.concat(files);
            vm.allItems = vm.allItems.concat(files);
            vm.rejected = rejectedFiles;
        };

        vm.fileLinked = function (link) {
            vm.links.push(link);
            vm.allItems.push(link);
        };

        vm.deleteAttachment = function (file) {
            removeFromArray(vm.links, file);
            removeFromArray(vm.attachments, file);
            removeFromArray(vm.allItems, file);
        };

        vm.fileValidate = function (file) {
            if (file.name.indexOf('a') === 0) {
                return 'You may not upload a file that begins with the letter "a."';
            }
        };

        vm.fileChange = function (file, rejectedFiles) {
            if (file) {
                vm.fileDropped([file], rejectedFiles);
            } else {
                vm.fileDropped([], rejectedFiles);
            }
        };

        vm.fileLinkAction = function () {
            alert(vm.singleFile.name);
        };

        $scope.$watch(function () {
            return vm.alertClosed;
        }, function () {
            if (vm.alertClosed) {
                vm.rejected = null;
                vm.alertClosed = false;
            }
        });
    }

    FileAttachmentDemoController.$inject = ['$scope'];

    angular.module('stache')
        .controller('FileAttachmentDemoController', FileAttachmentDemoController);

}());