J'écris une application web avec AngularJS et angular-material. Le problème est qu'il n'y a pas de composant intégré pour l'entrée de fichier en matériau angulaire. (Je pense que le téléchargement de fichiers ne correspond pas à la conception du matériau, mais j'en ai besoin dans mon application)
Avez-vous une bonne solution à ce problème?
Je trouve un moyen d'éviter de styler mon propre bouton de choix de fichier.
Parce que j'utilise flowjs pour un téléchargement pouvant être repris, je peux utiliser la directive " flow-btn " de ng-flow , qui donne un bouton de choix de fichier avec un style de conception de matériau. .
Notez que placer l’élément d’entrée dans un bouton md ne fonctionnera pas.
Belle solution de 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>
Voir dans codepen
Basé sur cette réponse . Il m'a fallu un certain temps pour que cette approche fonctionne, alors j'espère que ma réponse fera gagner du temps à quelqu'un.
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>
de jameswyse à 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>
MANETTE
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());
}
}
Travaillé pour moi.
Un autre exemple de la solution… .. ressemblera à ce qui suit
Lien CodePen il.
<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;
}
});
});
}
};
});
J'espère que ça aide!
Une autre solution piratée, bien que pourrait être un peu plus propre en implémentant un bouton Proxy:
HTML:
<input id="fileInput" type="file">
<md-button class="md-raised" ng-click="upload()">
<label>AwesomeButtonName</label>
</md-button>
JS:
app.controller('NiceCtrl', function ( $scope) {
$scope.upload = function () {
angular.element(document.querySelector('#fileInput')).click();
};
};
Vous pouvez changer le style en encapsulant l'entrée dans une étiquette et changer l'affichage d'entrée en aucun. Ensuite, vous pouvez spécifier le texte que vous souhaitez afficher dans un élément span. Remarque: ici, j'ai utilisé le style bootstrap 4 (btn btn-outline-primary). Vous pouvez utiliser n'importe quel style.
<label class="btn btn-outline-primary">
<span>Select File</span>
<input type="file">
</label>
input {
display: none;
}
En ajoutant à toutes les réponses ci-dessus (c’est pourquoi j’en ai fait un wiki de communauté), il vaut probablement mieux marquer input<type="text">
avec tabindex="-1"
, surtout si vous utilisez readonly au lieu de disabled (et peut-être le <input type="file">
, bien qu’il soit caché, toujours dans le document, apparemment). Les étiquettes n'ont pas agi correctement lors de l'utilisation des combinaisons de touches tabulation/entrée, mais le bouton l'a fait. Par conséquent, si vous copiez l'une des solutions proposées sur cette page, vous souhaiterez peut-être apporter ces modifications.
Pour 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>
Méthode du composant:
csvInputChange(fileInputEvent: any) {
console.log(fileInputEvent.target.files[0]);
}
Remarque: Ceci filtre pour autoriser uniquement les fichiers .csv
.