mdButton and FABs should be enhanced to support type="file" for built-in default triggers.
Currently this is the only way to use mdButton to support <input type="file">
:
To get <input type="file">
to work with mdButton, you must use a <label for="<link id>" />
. See below for working sample:
<html>
<head>
<link rel="stylesheet" href="https://rawgit.com/angular/bower-material/master/angular-material.css">
<style>
#file-input { display: none; }
</style>
<script src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
<script src="https://code.angularjs.org/1.4.0-beta.6/angular-animate.js"></script>
<script src="https://code.angularjs.org/1.4.0-beta.6/angular-aria.js"></script>
<script src="https://rawgit.com/angular/bower-material/master/angular-material.min.js"></script>
</head>
<body ng-app="app" >
<div>
<h2>File Upload with Material:</h2>
<md-button>
<label for="file-input">Select</label>
</md-button>
<input id="file-input" type="file">
</div>
<script>
angular.module('app', ['ngMaterial']);
</script>
</body>
</html>
@see Plunkr
Also need way to support this using FAB icon buttons. I think we use the above approach with nested mdIcon:
So
<md-button type="file" for="fileToUpload">
<md-icon md-font-icon="<name>" />
</md-button>
<input id="#fileToUpload" type="file" >
becomes
<md-button>
<label for="fileToUpload">
<md-icon md-font-icon="<name>" />
</label>
</md-button>
<input id="#fileToUpload" type="file style="display:none;">
This should work for fontIcons, but what about SVG icons using
md-icon-src="http://s3.postimg.org/mjzvuzi5b/uploader_image.png"
?
Nice one @ThomasBurleson!
I tried a modified version with md-fab
and md-svg-icon
and it only worked when the icon inside the button was clicked, if you click on the button outside the icon, it doesn't work, you only see the ripple effect. (on Chrome for Macos)
You can see here http://plnkr.co/edit/41Z5QWoc2JfZuuDVSOfB?p=preview
@cmoiccool - Try it again with the latest from #master. The SVG styles now use:
md-icon {
svg {
pointer-events: none;
}
}
Which then means that clicks are no longer captured by the svg.
It could also be that the <label>
isn't filling the button because it's an inline element. display: block;
in CSS may help.
@marcysutton - you are right. This is a bug.
label {
display:block;
}
works. Perhaps we should some CSS to compensate.
Perhaps:
.md-fab > label:[for] {
display:block;
}
@ThomasBurleson - The example on plnkr should already use #master through
<link rel="stylesheet" href="https://rawgit.com/angular/bower-material/master/angular-material.css">
<script src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
<script src="https://code.angularjs.org/1.4.0-beta.6/angular-animate.js"></script>
<script src="https://code.angularjs.org/1.4.0-beta.6/angular-aria.js"></script>
<script src="https://rawgit.com/angular/bower-material/master/angular-material.min.js"></script>
@marcysutton - I tried to add display: block;
to the <label>
and/or to the <md-button>
but it did not have any effect, it continues to get triggered only when the icon is clicked. Maybe I am not using the display: block
the way you are suggesting
I also tried label {
display:block;
}
and it is better now, only the right and left edges (probably because of some padding or margin) continue to only show the ripple effect
@ThomasBurleson The buttons work well if you open the file upload with js.
Also if anyone is interested in making a file upload ng-file-upload works very well.
ng-file-upload +1
Hey! I've been searching a way to fix once and for all this fix (because it has the problem that it doesn't work on some mobile devices):
<md-button class="md-fab" ng-disabled="progress">
<label for="upload_photo">
Upload
</label>
</md-button>
<input type="file" id="upload_photo">
I think I found it but I don't really know the actual structure of material-design and I don't have the time to teach myself. I found that this is a better way to put it once and for all in an <md-button type="file"></md-button>
or an <md-file><md-file>
.
Please take a look at this codepen and maybe try to adapt it if possible.
http://codepen.io/chriscoyier/pen/cvnCt
Thanks and keep up the good work!
@ThomasBurleson I couldn't get your solution to work in Firefox. Somehow the label inside the button doesn't seem to work there.
I adapted your Plunkr and added class="md-button"
directly on the label. This works and looks ok but the ripple is not working.
@kuhnroyal thanks for this temporary solution. I use it for now. Hope there will be a solution for this
@infacq I ended up writing a small directive, which fires a click event into the input element. This worked on all browsers I testet.
function click() {
$element.find('input')[0].click();
}
md-button.md-primary.md-raised(type="button" ng-click="click()" aria-label="Upload")
md-icon(md-svg-icon="editor:attach_file")
span Upload
input(type="file" multiple accept="application/pdf" style="visibility:hidden")
I updated the plunkr with md-ink-ripple
on the label. Now the ripple is working.
However it always uses the default theme, this would need some CSS enhancements to support themes.
@kuhnroyal Could you update the plunkr with the directive solution?
And thank you very very much!!!!!
What I finally ended up with is in that plunkr.
<label class="md-primary md-raised md-button" md-ink-ripple for="file-input">
<span>Select</span>
</label>
<label for="file-input">Select</label>
The only issues was the missing ink-ripple, which works now after adding the md-ink-ripple
directive to the label. I am using this across Chrome/IE/Firefox now.
I wrote this directive that works in CHrome/Safari/Firefox:
angular.module('app', ['ngMaterial'])
.directive('chooseFileButton', function() {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('click', function() {
angular.element(document.querySelector('#' + attrs.chooseFileButton))[0].click();
});
}
};
});
and html:
<md-button choose-file-button="file-input" aria-label="xxx"
class="md-fab" ng-click="">
<md-icon md-svg-icon="photo.svg"></md-icon>
</md-button>
<input id="file-input" type="file">
Thanks, MaximShoustin! I built off of your directive but tried to compartmentalize (i.e., avoid searching the entire document for the input element).
.directive('chooseFileButton', function() {
return {
restrict: 'E',
link: function (scope, elem, attrs) {
var button = elem.find('button');
var input = elem.find('input');
input.css({ display:'none' });
button.bind('click', function() {
input[0].click();
});
}
};
});
Then you can use the directive this way (the requirement is to include a button and a file input inside the element).
<choose-file-button>
<md-button aria-label="Upload a file" class="md-fab">
<md-icon class="fa" md-font-icon="fa-cloud-upload"></md-icon>
</md-button>
<input type="file">
</choose-file-button>
The File Picker feature has been deferred/bumped to a post-1.0 milestone.
@faustomorales thanks for that update! The code you provided works well and the isolation provided by the directive structure is great.
There is only one thing, I can't figure out how to then show the selected file. I'm thinking something with a change event but I can't figure it out. Any thoughts?
Happy it helped you! If all you really need is to show the file name, then yes, a change event will be sufficient. You can bind to changes on the input and use changeEvent.target.files[]
to access the file information. More details are available in this StackOverflow post.
If you need to upload the file, I highly recommend using something like danialfarid/ng-file-upload, which is what I usually use and will take care of getting the files for you (making the above unnecessary).
file upload should have features like on this article
@faustomorales your snippet doesn't work on Chrome, as it prevents selecting file from hidden inputs.
What version of Google Chrome? It works on 45.0.2454.85.
Mine is 45.0.2454.93.
Setting width and height to very small values, as suggested by @infacq, makes it work.
+1
My current solution to this is just allowing the template for md-button be a \
+1
This File Picker feature is really needed.
Why is has this been closed?
Any update on this? People want it, and it has unexpectedly been closed out of the blue...
At least an explanation would be nice.
@JonasT their explanation is that they are focusing on angular material 2, that uses angular 2.. so they decided to stop their development on this project.. just bug fixes will be done in here now
sometimes i think they shouldn't have done that as they are starting over again a material design project for angular, so to have the features that were being worked on, we are forced to go on other modules, other libraries that might not just work as good as angular material is, on the other side.. angular 2 is way too faster than angular 1, but is bad to leave a project that does not have all the features
Ran in to this same issue styling input type=file, so I hacked together a quick solution without having to make extra directives / etc.. Basically, render the regular HTML dialog, but with the ugly browse button BEHIND the cute material button. This is better than hiding the input control all together because you still can see the file name to let the user know which file they picked. Only using position:relative and z-index, so it should work on even the oldest browsers supported by angularjs 1.x.
HTML:
<label class="md-secondary md-raised md-button bring-forward" md-ink-ripple for="xFile">
<span>Select File</span>
</label>
<input type="file" ngf-select ng-model="xFile" name="xFile" id="xFile" class="file-input-hide">
CSS:
.file-input-hide {
position: relative;
left: -6em;
}
.bring-forward {
z-index:10;
}
Why is this closed? Please @ThomasBurleson reopen
Most helpful comment
My current solution to this is just allowing the template for md-button be a \