File Upload with Angular Material
Solution 1
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.
Solution 2
Nice solution by leocaseiro
<input class="ng-hide" id="input-file-id" multiple type="file" />
<label for="input-file-id" class="md-button md-raised md-primary">Choose Files</label>
View in codepen
Solution 3
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.
Solution 4
Another example of the solution. Will look like the following
CodePen link there.
<choose-file layout="row">
<input id="fileInput" type="file" class="ng-hide">
<md-input-container flex class="md-block">
<input type="text" ng-model="fileName" disabled>
<div class="hint">Select your file</div>
</md-input-container>
<div>
<md-button id="uploadButton" class="md-fab md-mini">
<md-icon class="material-icons">attach_file</md-icon>
</md-button>
</div>
</choose-file>
.directive('chooseFile', function() {
return {
link: function (scope, elem, attrs) {
var button = elem.find('button');
var input = angular.element(elem[0].querySelector('input#fileInput'));
button.bind('click', function() {
input[0].click();
});
input.bind('change', function(e) {
scope.$apply(function() {
var files = e.target.files;
if (files[0]) {
scope.fileName = files[0].name;
} else {
scope.fileName = null;
}
});
});
}
};
});
Hope it helps!
Solution 5
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.
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>
WreckingBall
Updated on June 17, 2021Comments
-
WreckingBall almost 3 years
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 doesn't fit the material design, but I need it in my app)
Do you have a good solution for this problem?
-
Leo Caseiro about 8 yearsThat's the easiest way. However, I'd switch the md-button for a label for="inputid", so you don't need to bind your click. The Label does but itself. Eq. <input class="ng-hide" id="FileUploadInput" multiple type="file" /> <label for="FileUploadInput" class="md-button md-raised md-primary">Choose Files</label>
-
krico about 8 yearsRather than using "disabled" on the input for "fileName" I used ng-readonly="true". But the idea in itself is the best!
-
Lucas Kuhlemann over 7 years@LeoCaseiro Care to put that in an answer?
-
Guy Schalnat almost 7 yearsHowever, if you want to actually give the user some feedback on the file they selected (like the
<input type="file">
does), then look at other solutions. -
Guy Schalnat almost 7 yearsAlso, the label doesn't behave correctly with the tab and enter keys, even if you put tabindex="0" on it.
-
Guy Schalnat almost 7 yearsAt least in 2017, the label doesn't seem to behave correctly using the tab / enter key combinations, while the button does.
-
Mendy over 4 yearsCan you explain why
onclick="this.value=null"
is necessary? -
rynop over 4 yearsIt forces a
change
event. Ex: you chooseme.jpg
and your Angular app displays a preview client side. You then notice yourme.jpg
isn't cropped correctly, so you modifyme.jpg
in photoshop, then go back to your webapp, click the button and chooseme.jpg
again. Without settingthis.value=null
your logic to re-render the image on the page would never fire. So not necessary, but it is good practice IMO. -
abhigyan nayak over 4 yearsNice try..But, I feel it does'nt support Multiple files
-
David Buck about 4 yearsWhile this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.
-
Sathiamoorthy almost 3 yearsPerfect example. Thank you
-
Patrick Prakash over 2 yearsSome edit suggestions this.selectedFiles = event.target.files will not work directly in angular now. Use this.selectedFiles = (event.target as HTMLInputElement).files;