J'essaie de créer une interface utilisateur dans laquelle se trouve un formulaire comportant deux champs de texte, un input type="file"
et une div
que vous pouvez supprimer des images à télécharger avec le reste du formulaire.
Mon objectif/logique
utilisez la même div
pour déposer une image ou cliquez dessus et ouvrez l'explorateur de dossiers comme le input type="file"
se comporte. Activer les clics est logique dans les petits écrans où il est pratiquement impossible de "glisser-déposer". Et comme il existe déjà un input type="file"
dans le formulaire, il n’ya aucune raison de prendre l’image de la variable div
et de l’ajouter au formulaire, etc. J'essaie de prendre l’image déposée dans la variable div
. input type="file"
et soumettez le formulaire une fois. (Si l'utilisateur a cliqué sur div
, alors le input type="file"
a déjà une valeur, je suis donc libre de soumettre le formulaire à nouveau).
Voici le code
<div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop>
</div>
<input type="file" formControlName="imageInput" required #imageInput id="imageInput" (change)='imageChange($event)' > <!-- use css to hide it -->
Ainsi, lorsque vous cliquez sur imageDrop
, appelez réellement la imageChange
via (click)='imageInput.click()'
C'est le TypeScript dans le composant.
//imageUpload is the name of the reactive form
acceptedImageTypes = {'image/png': true,'image/jpeg': true,'image/gif': true};
@ViewChild('imageDrop') imageDrop;
allowDrop(e) {
e.preventDefault();
}
drop(e) {
e.preventDefault();
//clear in case we selected something before via click
this.imageUpload.controls.imageInput.reset();
this.imageDrop.innerHTML="";
this.checkfiles(e.dataTransfer.files);
}
imageChange(event){
this.imageDrop.innerHTML="";
this.checkfiles(event.target.files);
}//imageChange
checkfiles(files){
if (this.acceptedImageTypes[files[0].type] !== true){
this.imageDrop.nativeElement.innerHTML="Not an image";
return;
}
else if (files.length>1){
this.imageDrop.nativeElement.innerHTML="Only one image/time";
return;
}
else { this.readfiles(files); }
}//checkfiles
readfiles(files){
const reader = new FileReader();
let image = new Image();
reader.onload = (event) =>{
this.imageDrop.nativeElement.innerHTML="";
let fileReader = event.target as FileReader;
image.src = fileReader.result;
image.width = 150;
this.imageDrop.nativeElement.appendChild(image);
};
reader.readAsDataURL(files[0]);
if (this.imageUpload.controls.imageInput.value==null) {
//if its null then means that we dragging an img, so the previous image from the input file is deleted
//now we got to put this image to the input file in order to submit the form
this.imageUpload.controls.imageInput.reset(files[0] );
}
}//readfiles
imageUploadSubmitted(){
//when form submit, for now just check image value to check if its the right one
console.log('IMAGE VALUE SUBMIT = = ',this.imageUpload.controls.imageInput.value);
}
Les erreurs
Lorsque j'essaie de faire glisser/déposer une image, j'obtiens ce ERROR DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string
qui pointe vers cette ligne HTML <div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop>
mais je suis sûr que cela est lié au
if (this.imageUpload.controls.imageInput.value==null) {
this.imageUpload.controls.imageInput.reset(files[0] );
}
partie de la fonction readfiles
.
Des idées sur la façon de résoudre ce problème afin que le fichier puisse obtenir une valeur et être ensuite libre de soumettre le formulaire?
Merci
Ok, la ligne qui vous a donné l'erreur était this.imageUpload.controls.imageInput.setValue(files[0]);
La raison en est que le navigateur vous empêchera de définir le fichier de cette manière par programme en raison de problèmes de sécurité.
Au lieu de cela, vous pouvez utiliser le e.dataTransfer.files
directement:
let input = this.imageUpload.controls.imageInput as any;
input.files = files;
Ce que vous essayez de faire ne peut pas être réalisé de cette façon (cause de ce que tout le monde a dit, raison de sécurité, etc.).
Pour réaliser ce que vous voulez faire, une solution Angular consiste à créer un composant personnalisé utilisant [(ngModel)] formControlName en implémentant le ControlValueAccessor.
En faisant cela, vous pourrez mettre ce que vous voulez comme valeur dans FormControl.
L'implémentation de ControlValueAccessor fait partie de plusieurs tutoriels: https://blog.angularindepth.com/never-again-be-confused-when-implementing-controlvalueaccessor-in-angular-forms-93b9eee9ee83
Ici vous pouvez trouver mon propre code, un sélecteur d’images travaillant dans un formulaire:
exemple: https://ng-tools.asi.fr/views/showroom/asi-ngtools/components/asi-image-chooser