File Upload with Angular Material

后端 未结 12 1054
抹茶落季
抹茶落季 2021-01-30 15:48

I\'m writing an web app with AngularJS and angular-material. The problem is that there\'s no built-in component for file input in angular-material. (I feel that file uploading d

相关标签:
12条回答
  • 2021-01-30 16:42

    You can change the style by wrapping the input inside a label and change the input display to none. Then, you can specify the text you want to be displayed inside a span element. Note: here I used bootstrap 4 button style (btn btn-outline-primary). You can use any style you want.

    <label class="btn btn-outline-primary">
          <span>Select File</span>
          <input type="file">
    </label>
    
    input {
      display: none;
    }
    
    0 讨论(0)
  • 2021-01-30 16:44

    For Angular 6+:

    HTML:

    <input #csvInput hidden="true" type="file" onclick="this.value=null" (change)="csvInputChange($event)" accept=".csv"/>
    <button mat-flat-button color="primary" (click)="csvInput.click()">Choose Spreadsheet File (CSV)</button>
    

    Component method:

      csvInputChange(fileInputEvent: any) {
        console.log(fileInputEvent.target.files[0]);
      }
    

    Note: This filters to just allow .csv files.

    0 讨论(0)
  • 2021-01-30 16:44

    from jameswyse at https://github.com/angular/material/issues/3310

    HTML

    <input id="fileInput" name="file" type="file" class="ng-hide" multiple>
    <md-button id="uploadButton" class="md-raised md-primary"> Choose Files </md-button>
    

    CONTROLLER

        var link = function (scope, element, attrs) {
        const input = element.find('#fileInput');
        const button = element.find('#uploadButton');
    
        if (input.length && button.length) {
            button.click((e) => input.click());
        }
    }
    

    Worked for me.

    0 讨论(0)
  • 2021-01-30 16:45

    File uploader with AngularJs Material and a mime type validation:

    Directive:

    function apsUploadFile() {
        var directive = {
            restrict: 'E',
            require:['ngModel', 'apsUploadFile'],
            transclude: true,
            scope: {
                label: '@',
                mimeType: '@',
            },
            templateUrl: '/build/html/aps-file-upload.html',
            controllerAs: 'ctrl',
            controller: function($scope) {
                var self = this;
    
                this.model = null;
    
                this.setModel = function(ngModel) {
                    this.$error = ngModel.$error;
    
                    ngModel.$render = function() {
                        self.model = ngModel.$viewValue;
                    };
    
                    $scope.$watch('ctrl.model', function(newval) {
                        ngModel.$setViewValue(newval);
                    });
                };
            },
            link: apsUploadFileLink
        };
        return directive;
    }
    
    function apsUploadFileLink(scope, element, attrs, controllers) {
    
        var ngModelCtrl = controllers[0];
        var apsUploadFile = controllers[1];
    
        apsUploadFile.inputname = attrs.name;
        apsUploadFile.setModel(ngModelCtrl);
    
        var reg;
        attrs.$observe('mimeType', function(value) {
            var accept = value.replace(/,/g,'|');
            reg = new RegExp(accept, "i");
            ngModelCtrl.$validate();
        });
    
        ngModelCtrl.$validators.mimetype = function(modelValue, viewValue) {
    
            if(modelValue.data == null){
                return apsUploadFile.valid = true;
            }
    
            if(modelValue.type.match(reg)){
                return apsUploadFile.valid = true;
            }else{
                return apsUploadFile.valid = false;
            }
    
        };
    
        var input = $(element[0].querySelector('#fileInput'));
        var button = $(element[0].querySelector('#uploadButton'));
        var textInput = $(element[0].querySelector('#textInput'));
    
        if (input.length && button.length && textInput.length) {
            button.click(function(e) {
                input.click();
            });
            textInput.click(function(e) {
                input.click();
            });
        }
    
        input.on('change', function(e) {
    
            //scope.fileLoaded(e);
            var files = e.target.files;
    
            if (files[0]) {
                ngModelCtrl.$viewValue.filename = scope.filename = files[0].name;
                ngModelCtrl.$viewValue.type = files[0].type;
                ngModelCtrl.$viewValue.size = files[0].size;
    
                var fileReader = new FileReader();
                fileReader.onload = function () {
                    ngModelCtrl.$viewValue.data = fileReader.result;
                    ngModelCtrl.$validate();
                };
                fileReader.readAsDataURL(files[0]);
    
                ngModelCtrl.$render();
            } else {
                ngModelCtrl.$viewValue = null;
            }
    
            scope.$apply();
        });
    
    }
    app.directive('apsUploadFile', apsUploadFile);
    

    html template:

    <input id="fileInput" type="file" name="ctrl.inputname" class="ng-hide">
    <md-input-container md-is-error="!ctrl.valid">
        <label>{@{label}@}</label>
        <input id="textInput" ng-model="ctrl.model.filename" type="text" ng-readonly="true">
        <div ng-messages="ctrl.$error" ng-transclude></div>
    </md-input-container>
    <md-button id="uploadButton" class="md-icon-button md-primary" aria-label="attach_file">
        <md-icon class="material-icons">cloud_upload</md-icon>
    </md-button>
    

    Exemple:

    <div layout-gt-sm="row">
        <aps-upload-file name="strip" ng-model="cardDesign.strip" label="Strip" mime-type="image/png" class="md-block">
            <div ng-message="mimetype" class="md-input-message-animation ng-scope" style="opacity: 1; margin-top: 0px;">Your image must be PNG.</div>
        </aps-upload-file>
    </div>
    
    0 讨论(0)
  • 2021-01-30 16:50

    Based on this answer. It took some time for me to make this approach working, so I hope my answer will save someone's time.

    DEMO on CodePen

    Directive:

    angular.module('app').directive('apsUploadFile', apsUploadFile);
    
    function apsUploadFile() {
        var directive = {
            restrict: 'E',
            templateUrl: 'upload.file.template.html',
            link: apsUploadFileLink
        };
        return directive;
    }
    
    function apsUploadFileLink(scope, element, attrs) {
        var input = $(element[0].querySelector('#fileInput'));
        var button = $(element[0].querySelector('#uploadButton'));
        var textInput = $(element[0].querySelector('#textInput'));
    
        if (input.length && button.length && textInput.length) {
            button.click(function (e) {
                input.click();
            });
            textInput.click(function (e) {
                input.click();
            });
        }
    
        input.on('change', function (e) {
            var files = e.target.files;
            if (files[0]) {
                scope.fileName = files[0].name;
            } else {
                scope.fileName = null;
            }
            scope.$apply();
        });
    }
    

    upload.file.template.html

    <input id="fileInput" type="file" class="ng-hide">
    <md-button id="uploadButton"
               class="md-raised md-primary"
               aria-label="attach_file">
        Choose file
    </md-button>
    <md-input-container md-no-float>
        <input id="textInput" ng-model="fileName" type="text" placeholder="No file chosen" ng-readonly="true">
    </md-input-container>
    
    0 讨论(0)
  • 2021-01-30 16:52

    I find a way to avoid styling my own choose file button.

    Because I'm using flowjs for resumable upload, I'm able to use the "flow-btn" directive from ng-flow, which gives a choose file button with material design style.

    Note that wrapping the input element inside a md-button won't work.

    0 讨论(0)
提交回复
热议问题