Comment puis-je détecter lorsque l'utilisateur annule une entrée de fichier à l'aide d'une entrée de fichier html?
onChange me permet de détecter quand ils choisissent un fichier, mais j'aimerais aussi savoir quand ils s'annulent (fermez la boîte de dialogue de choix de fichier sans rien sélectionner).
e.target.files
Réponses:
Bien que ce ne soit pas une solution directe, et également mauvaise en ce sens qu'elle fonctionne uniquement (pour autant que j'ai testé) avec onfocus (nécessitant un blocage d'événements assez limitatif), vous pouvez y parvenir avec les éléments suivants:
Ce qui est bien à ce sujet, c'est que vous pouvez l'attacher / le détacher à temps avec l'événement de fichier, et cela semble également fonctionner correctement avec les entrées cachées (un avantage certain si vous utilisez une solution de contournement visuelle pour le type d'entrée par défaut merdique = ' fichier'). Après cela, il vous suffit de déterminer si la valeur d'entrée a changé.
Un exemple:
Voyez-le en action: http://jsfiddle.net/Shiboe/yuK3r/6/
Malheureusement, cela ne semble fonctionner que sur les navigateurs Webkit. Peut-être que quelqu'un d'autre peut trouver la solution Firefox / IE
la source
addEventListener("focus",fn,{once: true})
. Cependant, je n'ai pas pu le faire tirer du tout en utilisantdocument.body.addEventListener
... Je ne sais pas pourquoi. Au lieu de cela, j'ai obtenu le même résultat avecwindow.addEventListener
.mousemove
événement surwindow.document
en plus d'écouterfocus
surwindow
semble fonctionner partout (au moins dans les navigateurs modernes, je me fiche des épaves des dix dernières années). Fondamentalement, tout événement d'interaction peut être utilisé pour cette tâche qui est bloquée par une boîte de dialogue d'ouverture de fichier ouverte.Vous ne pouvez pas.
Le résultat de la boîte de dialogue de fichier n'est pas exposé au navigateur.
la source
change
événement n'est distribué.change
événement n'est distribué pour cela non plus.Je vais donc jeter mon chapeau sur cette question depuis que j'ai trouvé une nouvelle solution. J'ai une application Web progressive qui permet aux utilisateurs de capturer des photos et des vidéos et de les télécharger. Nous utilisons WebRTC lorsque cela est possible, mais revenons aux sélecteurs de fichiers HTML5 pour les appareils avec moins de support * toux Safari toux *. Si vous travaillez spécifiquement sur une application Web mobile Android / iOS qui utilise l'appareil photo natif pour capturer directement des photos / vidéos, c'est la meilleure solution que j'ai rencontrée.
Le nœud de ce problème est que lorsque la page se charge, le
file
estnull
, mais lorsque l'utilisateur ouvre la boîte de dialogue et appuie sur "Annuler", lefile
est toujoursnull
, donc il n'a pas "changé", donc aucun événement "changement" n'est déclenché. Pour les ordinateurs de bureau, ce n'est pas si mal, car la plupart des interfaces utilisateur de bureau ne dépendent pas du fait de savoir quand une annulation est invoquée, mais les interfaces utilisateur mobiles qui font apparaître l'appareil photo pour capturer une photo / vidéo dépendent beaucoup de savoir quand une annulation est activée.J'ai initialement utilisé l'
document.body.onfocus
événement pour détecter le retour de l'utilisateur depuis le sélecteur de fichiers, et cela a fonctionné pour la plupart des appareils, mais iOS 11.3 l'a cassé car cet événement n'est pas déclenché.Concept
Ma solution à cela est * frémir * pour mesurer la synchronisation du processeur pour déterminer si la page est actuellement au premier plan ou en arrière-plan. Sur les appareils mobiles, le temps de traitement est donné à l'application actuellement au premier plan. Lorsqu'une caméra est visible, elle volera du temps CPU et dépriorisera le navigateur. Tout ce que nous avons à faire est de mesurer le temps de traitement accordé à notre page, lorsque la caméra démarre, notre temps disponible diminue considérablement. Lorsque la caméra est rejetée (annulée ou non), notre temps disponible augmente.
la mise en oeuvre
Nous pouvons mesurer la synchronisation du processeur en utilisant
setTimeout()
pour appeler un rappel en X millisecondes, puis mesurer le temps qu'il a fallu pour l'invoquer. Le navigateur ne l'invoquera jamais exactement après X millisecondes, mais s'il est raisonnablement proche, nous devons être au premier plan. Si le navigateur est très loin (plus de 10 fois plus lent que demandé), nous devons être en arrière-plan. Une implémentation de base de ceci est comme ceci:J'ai testé cela sur une version récente d'iOS et d'Android, en faisant apparaître la caméra native en définissant les attributs sur l'
<input />
élément.Cela fonctionne en fait beaucoup mieux que ce à quoi je m'attendais. Il exécute 10 essais en demandant qu'un minuteur soit appelé en 25 millisecondes. Il mesure ensuite combien de temps il a réellement fallu pour invoquer, et si la moyenne de 10 essais est inférieure à 50 millisecondes, nous supposons que nous devons être au premier plan et que la caméra est partie. Si elle est supérieure à 50 millisecondes, alors nous devons toujours être en arrière-plan et continuer à attendre.
Quelques détails supplémentaires
J'ai utilisé
setTimeout()
plutôt quesetInterval()
parce que ce dernier peut mettre en file d'attente plusieurs invocations qui s'exécutent immédiatement les unes après les autres. Cela pourrait augmenter considérablement le bruit dans nos données, donc je suis resté avecsetTimeout()
même si c'est un peu plus compliqué à faire.Ces chiffres particuliers ont bien fonctionné pour moi, même si j'ai vu au moins une fois où le rejet de la caméra a été détecté prématurément. Je pense que c'est parce que la caméra peut être lente à s'ouvrir et que l'appareil peut exécuter 10 essais avant de devenir réellement en arrière-plan. L'ajout d'essais supplémentaires ou l'attente de 25 à 50 millisecondes avant de démarrer cette fonction peut être une solution de contournement pour cela.
Bureau
Malheureusement, cela ne fonctionne pas vraiment pour les navigateurs de bureau. En théorie, la même astuce est possible car ils donnent la priorité à la page actuelle par rapport aux pages en arrière-plan. Cependant, de nombreux bureaux disposent de suffisamment de ressources pour que la page continue à fonctionner à pleine vitesse, même en arrière-plan, cette stratégie ne fonctionne donc pas vraiment dans la pratique.
Solutions alternatives
Une solution alternative que peu de gens mentionnent que j'ai explorée était de se moquer d'un
FileList
. Nous commençons parnull
dans<input />
et puis si l'utilisateur ouvre la caméra et annule, il revientnull
, ce qui n'est pas un changement et aucun événement ne se déclenchera. Une solution consisterait à attribuer un fichier factice<input />
au début de la page. Par conséquent, définir surnull
serait un changement qui déclencherait l'événement approprié.Malheureusement, il n'y a aucun moyen officiel de créer un
FileList
, et l'<input />
élément nécessite unFileList
en particulier et n'acceptera aucune autre valeur en plusnull
. Naturellement, lesFileList
objets ne peuvent pas être construits directement, à cause d'un vieux problème de sécurité qui n'est même plus pertinent apparemment. Le seul moyen d'en obtenir un en dehors d'un<input />
élément est d'utiliser un hack qui copie-colle des données pourFileList
simuler un événement de presse-papiers pouvant contenir un objet (vous simulez essentiellement un glisser-déposer d'un fichier sur -votre-événement de site Web). C'est possible dans Firefox, mais pas pour iOS Safari, donc ce n'était pas viable pour mon cas d'utilisation particulier.Navigateurs, s'il vous plaît ...
Inutile de dire que c'est manifestement ridicule. Le fait que les pages Web ne reçoivent aucune notification indiquant qu'un élément critique de l'interface utilisateur a changé est tout simplement risible. C'est vraiment un bogue dans la spécification, car il n'a jamais été destiné à une interface utilisateur de capture multimédia en plein écran, et ne pas déclencher l'événement "changement" est techniquement conforme aux spécifications.
Cependant , les fournisseurs de navigateurs peuvent-ils reconnaître la réalité de cela? Cela peut être résolu soit avec un nouvel événement "done" qui est déclenché même lorsqu'aucun changement ne se produit, soit vous pouvez simplement déclencher "change" de toute façon. Ouais, ce serait contraire aux spécifications, mais il est trivial pour moi de déduire un événement de changement du côté JavaScript, mais fondamentalement impossible d'inventer mon propre événement "terminé". Même ma solution n'est vraiment qu'une heuristique, si elle n'offre aucune garantie sur l'état du navigateur.
Dans l'état actuel des choses, cette API est fondamentalement inutilisable pour les appareils mobiles, et je pense qu'un changement de navigateur relativement simple pourrait rendre cela infiniment plus facile pour les développeurs Web * sort de la boîte à savon *.
la source
Lorsque vous sélectionnez un fichier et cliquez sur ouvrir / annuler, l'
input
élément devrait perdre le focus akablur
. En supposant que l'initialevalue
deinput
est vide, toute valeur non vide dans votreblur
gestionnaire indiquerait un OK, et une valeur vide signifierait un Cancel.UPDATE: Le
blur
n'est pas déclenché lorsque leinput
est masqué. Vous ne pouvez donc pas utiliser cette astuce avec les téléchargements basés sur IFRAME, à moins que vous ne souhaitiez afficher temporairement le fichierinput
.la source
blur
ne se déclenche pas lorsque vous sélectionnez un fichier. Je n'ai pas essayé dans d'autres navigateurs.la source
else
déclaration est déjà évaluée?La plupart de ces solutions ne fonctionnent pas pour moi.
Le problème est que vous ne savez jamais quel événement sera déclenché, n'est-ce pas
click
ou est-cechange
? Vous ne pouvez assumer aucun ordre, car cela dépend probablement de l'implémentation du navigateur.Au moins dans Opera et Chrome (fin 2015)
click
est déclenché juste avant de `` remplir '' l'entrée avec des fichiers, vous ne saurez donc jamais la duréefiles.length != 0
jusqu'à ce que vous retardiezclick
d'être déclenché aprèschange
.Voici le code:
la source
Écoutez également l'événement de clic.
À la suite de l'exemple de Shiboe, voici un exemple jQuery:
Vous pouvez le voir en action ici: http://jsfiddle.net/T3Vwz
la source
Vous pouvez attraper l'annulation si vous choisissez le même fichier que précédemment et que vous cliquez sur annuler: dans ce cas.
Vous pouvez le faire comme ceci:
la source
Le moyen le plus simple est de vérifier s'il y a des fichiers dans la mémoire temporaire. Si vous souhaitez obtenir l'événement de modification chaque fois que l'utilisateur clique sur l'entrée de fichier, vous pouvez le déclencher.
la source
La solution de Shiboe serait bonne si elle fonctionnait sur le webkit mobile, mais ce n'est pas le cas. Ce que je peux proposer, c'est d'ajouter un écouteur d'événement mousemove à un objet dom au moment où la fenêtre d'entrée de fichier est ouverte, comme ceci:
L'événement mousemove est bloqué de la page pendant que la boîte de dialogue de fichier est ouverte, et quand elle est fermée, on vérifie s'il y a des fichiers dans l'entrée de fichier. Dans mon cas, je veux un indicateur d'activité bloquant les choses jusqu'à ce que le fichier soit téléchargé, donc je veux uniquement supprimer mon indicateur lors de l'annulation.
Cependant, cela ne résout pas pour le mobile, car il n'y a pas de souris à déplacer. Ma solution est loin d'être parfaite, mais je pense qu'elle est assez bonne.
Maintenant, nous écoutons une touche sur l'écran pour faire la même vérification des fichiers. Je suis assez confiant que le doigt de l'utilisateur sera mis sur l'écran assez rapidement après l'annulation et le rejet de cet indicateur d'activité.
On pourrait également simplement ajouter l'indicateur d'activité sur l'événement de changement d'entrée de fichier, mais sur mobile, il y a souvent un décalage de quelques secondes entre la sélection de l'image et le déclenchement de l'événement de changement, donc c'est juste une bien meilleure UX pour l'indicateur d'activité à afficher sur le début du processus.
la source
J'ai trouvé cet attribut, le plus simple à ce jour.
Ici,
selectedFile
est uninput type=file
.la source
Je sais que c'est une question très ancienne, mais juste au cas où cela aiderait quelqu'un, j'ai trouvé en utilisant l'événement onmousemove pour détecter l'annulation, qu'il était nécessaire de tester deux ou plusieurs événements de ce type dans un court laps de temps. Cela était dû au fait que des événements onmousemove uniques sont générés par le navigateur (Chrome 65) chaque fois que le curseur est déplacé hors de la fenêtre de dialogue de sélection de fichier et chaque fois qu'il est déplacé hors de la fenêtre principale et de retour. Un simple compteur d'événements de mouvement de la souris couplé à un délai d'expiration de courte durée pour remettre le compteur à zéro a fonctionné un régal.
la source
Dans mon cas, j'ai dû masquer le bouton de soumission pendant que les utilisateurs sélectionnaient des images.
Voici ce que je viens de dire:
#image-field
est mon sélecteur de fichiers. Lorsque quelqu'un clique dessus, je désactive le bouton d'envoi du formulaire. Le fait est que lorsque la boîte de dialogue de fichier s'est fermée - peu importe qu'ils sélectionnent un fichier ou s'annulent -#image-field
le focus est revenu, alors j'écoute cet événement.METTRE À JOUR
J'ai trouvé que cela ne fonctionne pas en safari et poltergeist / phantomjs. Tenez compte de ces informations si vous souhaitez l'implémenter.
la source
En combinant les solutions de Shiboe et d'alx, j'ai le code le plus fiable:
Généralement, l'événement mousemove fait l'affaire, mais au cas où l'utilisateur aurait fait un clic et que:
... nous n'obtiendrons pas d'événement mousemove, donc pas de rappel d'annulation. De plus, si l'utilisateur annule la deuxième boîte de dialogue et déplace la souris, nous obtiendrons 2 rappels d'annulation. Heureusement, les événements spéciaux jQuery focusIn remontent au document dans les deux cas, ce qui nous aide à éviter de telles situations. La seule limitation est si l'on bloque l'événement focusIn non plus.
la source
mousemove
événementdocument
lors de la sélection de fichiers dans la boîte de dialogue du système d'exploitation dans Chrome 56.0.2924.87 sur Ubuntu 16.10. Pas de problème, lorsque vous ne déplacez pas la souris ou que vous n'utilisez que le clavier pour sélectionner le fichier. J'ai dû remplacermousemove
parkeydown
pour détecter l'annulation le plus tôt possible, mais pas "trop tôt", alors que la boîte de dialogue était encore ouverte.Je vois que ma réponse serait assez dépassée, mais jamais moins. J'ai fait face au même problème. Alors voici ma solution. Le code le plus utile était celui de KGA. Mais cela ne fonctionne pas totalement et c'est un peu compliqué. Mais je l'ai simplifié.
En outre, le principal problème était que l'événement de «changement» ne survient pas instantanément après la mise au point, nous devons donc attendre un certain temps.
"#appendfile" - sur lequel l'utilisateur clique pour ajouter un nouveau fichier. Les Hrefs reçoivent des événements de focus.
la source
Vous ne pouvez le détecter que dans des circonstances limitées. Plus précisément, dans Chrome, si un fichier a été sélectionné plus tôt et que la boîte de dialogue de fichier est cliquée et annulée, Chrome efface le fichier et déclenche l'événement onChange.
https://code.google.com/p/chromium/issues/detail?id=2508
Dans ce scénario, vous pouvez le détecter en gérant l'événement onChange et en vérifiant la propriété files .
la source
Ce qui suit semble fonctionner pour moi (sur le bureau, Windows):
Cela utilise angularjs $ q mais vous devriez pouvoir le remplacer par n'importe quel autre framework de promesse si nécessaire.
Testé sur IE11, Edge, Chrome, Firefox, mais il ne semble pas fonctionner sur Chrome sur une tablette Android car il ne déclenche pas l'événement Focus.
la source
Le
file
champ -type, de manière frustrante, ne répond pas à beaucoup d'événements (le flou serait bien). Je vois beaucoup de gens suggérer deschange
solutions orientées et être critiqués.change
fonctionne, mais il a un défaut majeur (par rapport à ce que nous voulons qu'il se passe).Lorsque vous chargez fraîchement une page contenant un champ de fichier, ouvrez la boîte et appuyez sur Annuler. Rien, frustrant, ne change .
Ce que j'ai choisi de faire est de charger dans un état fermé.
section#after-image
dans mon cas est masquée à la vue. Lorsque mesfile field
modifications, un bouton de téléchargement s'affiche. Une fois le téléchargement réussi,section#after-image
s'affiche.change
événement est déclenché par cette annulation, et là je peux (et je fais) re-cacher mon bouton de téléchargement jusqu'à ce qu'un fichier approprié soit sélectionné.J'ai eu la chance que cet état fermé soit déjà la conception de ma forme. Vous n'avez pas besoin d'utiliser le même style, simplement avoir le bouton de téléchargement initialement masqué et lors du changement, définir un champ masqué ou une variable javascript sur quelque chose que vous pouvez surveiller lors de la soumission.
J'ai essayé de changer la valeur des fichiers [0] avant que le champ n'interagisse. Cela n'a rien fait concernant onchange.
Alors oui, ça
change
marche, au moins aussi bien que ce que nous allons obtenir. Le champ de fichiers est sécurisé, pour des raisons évidentes, mais à la frustration des développeurs bien intentionnés.Cela ne correspond pas à mon objectif, mais vous pourrez peut-être
onclick
, charger une invite d'avertissement (pas unealert()
, car cela bloque le traitement des pages), et la masquer si un changement est déclenché et que les fichiers [0] sont nuls. Si le changement n'est pas déclenché, le div reste dans son état.la source
Il existe un moyen malveillant de le faire (ajouter des rappels ou résoudre une implémentation différée / promise au lieu d'
alert()
appels):Fonctionnement: lorsque la boîte de dialogue de sélection de fichier est ouverte, le document ne reçoit pas les événements du pointeur de la souris. Il y a un délai de 1000 ms pour permettre à la boîte de dialogue d'apparaître et de bloquer la fenêtre du navigateur. Enregistré dans Chrome et Firefox (Windows uniquement).
Mais ce n'est pas un moyen fiable de détecter les dialogues annulés, bien sûr. Cependant, cela pourrait améliorer certains comportements de l'interface utilisateur pour vous.
la source
Voici ma solution, en utilisant le focus d'entrée de fichier (sans utiliser de minuteries)
la source
Error: { "message": "Uncaught SyntaxError: missing ) after argument list", "filename": "https://stacksnippets.net/js", "lineno": 51, "colno": 1 }
C'est au mieux piraté, mais voici un exemple fonctionnel de ma solution pour détecter si un utilisateur a téléchargé un fichier ou non, et ne lui permettre de continuer que s'il a téléchargé un fichier.
Fondamentalement , le cacher
Continue
,Save
,Proceed
ou quel que soit votre bouton est. Ensuite, dans le JavaScript, vous saisissez le nom du fichier. Si le nom de fichier n'a pas de valeur, n'affichez pas leContinue
bouton. S'il a une valeur, affichez le bouton. Cela fonctionne également s'ils téléchargent d'abord un fichier, puis essaient de télécharger un autre fichier et cliquent sur Annuler.Voici le code.
HTML:
JavaScript:
CSS:
Pour le CSS, cela consiste en grande partie à rendre le site Web et le bouton accessibles à tous. Personnalisez votre bouton comme vous le souhaitez.
la source
Eh bien, cela ne répond pas exactement à votre question. Mon hypothèse est que, vous avez un scénario, lorsque vous ajoutez une entrée de fichier et invoquez la sélection de fichier, et si l'utilisateur frappe l'annulation, vous supprimez simplement l'entrée.
Si tel est le cas, alors: Pourquoi ajouter une entrée de fichier vide?
Créez celui-ci à la volée, mais ajoutez-le au DOM uniquement lorsqu'il est rempli. Comme ceci:
Donc ici, je crée <input type = "file" /> à la volée, je me lie à son événement de changement et j'appelle immédiatement click. Lors d'un changement, il ne se déclenchera que lorsque l'utilisateur sélectionne un fichier et clique sur Ok, sinon l'entrée ne sera pas ajoutée au DOM, donc ne sera pas soumise.
Exemple de travail ici: https://jsfiddle.net/69g0Lxno/3/
la source
// Utiliser le survol au lieu du flou
la source
Si vous avez déjà besoin de JQuery, cette solution pourrait faire le travail (c'est exactement le même code dont j'avais réellement besoin dans mon cas, bien que l'utilisation d'une promesse consiste simplement à forcer le code à attendre que la sélection de fichier soit résolue):
});
la source
Il existe plusieurs solutions proposées dans ce fil et cette difficulté à détecter lorsque l'utilisateur clique sur le bouton "Annuler" de la boîte de sélection de fichiers est un problème qui affecte de nombreuses personnes.
Le fait est qu'il n'existe pas de moyen fiable à 100% pour détecter si l'utilisateur a cliqué sur le bouton "Annuler" de la boîte de sélection de fichiers. Mais il existe des moyens de détecter de manière fiable si l'utilisateur a ajouté un fichier au fichier d'entrée. Voilà donc la stratégie de base de cette réponse!
J'ai décidé d'ajouter cette réponse car apparemment les autres réponses ne fonctionnent pas sur la plupart des navigateurs ou sont garanties sur les appareils mobiles.
En bref, le code est basé sur 3 points:
Pour une meilleure compréhension, regardez également le code ci-dessous et les notes.
Merci! = D
la source
Nous avons réalisé en angulaire comme ci-dessous.
HTML
TS
la source
Ajoutez simplement un écouteur 'change' sur votre entrée dont le type est fichier. c'est à dire
J'ai fini d'utiliser jQuery et évidemment tout le monde peut utiliser valina JS (selon l'exigence).
la source
.change()
n'est pas appelé de manière fiable si l'utilisateur clique sur "annuler" sur le sélecteur de fichiers.la source
Solution pour la sélection de fichiers avec entrée masquée
Remarque: ce code ne détecte pas l'annulation, il offre un moyen de contourner le besoin de le détecter dans un cas courant où les gens essaient de le détecter.
Je suis arrivé ici en cherchant une solution pour les téléchargements de fichiers en utilisant une entrée cachée, je pense que c'est la raison la plus courante pour rechercher un moyen de détecter l'annulation de l'entrée de fichier (ouvrir la boîte de dialogue de fichier -> si un fichier a été sélectionné, exécutez-en code, sinon ne rien faire), voici ma solution:
Exemple d'utilisation:
Notez que si aucun fichier n'a été sélectionné alors la première ligne ne retournera qu'une seule fois
selectFile()
est appelée à nouveau (ou si vous avez appeléfileSelectorResolve()
depuis un autre endroit).Un autre exemple:
la source
Vous pouvez créer un écouteur de changement jquery sur le champ de saisie et détecter que l'utilisateur annule ou ferme la fenêtre de téléchargement par la valeur du champ.
Voici un exemple:
la source