web-dev-qa-db-fra.com

Comment puis-je déclencher l'événement click d'un autre élément dans ng-click en utilisant angularjs?

J'essaie de déclencher l'événement click de l'élément <input type="file"> à partir de la variable button.

<input id="upload"
    type="file"
    ng-file-select="onFileSelect($files)"
    style="display: none;">

<button type="button"
    ng-click="angular.element('#upload').trigger('click');">Upload</button>

Il est courant de cacher la bête abominable appelée <input type=file> et de déclencher son événement clic par un autre moyen.

42
chovy

Si votre entrée et votre bouton sont frères (et ils sont dans votre cas OP):

<input id="upload"
    type="file"
    ng-file-select="onFileSelect($files)"
    style="display: none;">

<button type="button" uploadfile>Upload</button>

Utilisez une directive pour lier le clic de votre bouton au fichier en entrée de la manière suivante:

app.directive('uploadfile', function () {
    return {
      restrict: 'A',
      link: function(scope, element) {

        element.bind('click', function(e) {
            angular.element(e.target).siblings('#upload').trigger('click');
        });
      }
    };
});
34
J Savage Uphoff

C'était donc une solution simple. Il suffisait de déplacer le ng-click vers un gestionnaire de clic sur l'étendue:

<input id="upload"
    type="file"
    ng-file-select="onFileSelect($files)"
    style="display: none;">

<button type="button"
    ng-click="clickUpload()">Upload</button>



$scope.clickUpload = function(){
    angular.element('#upload').trigger('click');
};
13
chovy

J'ai eu le même problème et ce violon est le shizzle :) Il utilise une directive pour styler correctement le champ de fichier et vous pouvez même en faire une image ou autre.

http://jsfiddle.net/stereosteve/v5Rdc/7/

/*globals angular:true*/
var buttonApp = angular.module('buttonApp', [])

buttonApp.directive('fileButton', function() {
  return {
    link: function(scope, element, attributes) {

      var el = angular.element(element)
      var button = el.children()[0]

      el.css({
        position: 'relative',
        overflow: 'hidden',
        width: button.offsetWidth,
        height: button.offsetHeight
      })

      var fileInput = angular.element('<input type="file" multiple />')
      fileInput.css({
        position: 'absolute',
        top: 0,
        left: 0,
        'z-index': '2',
        width: '100%',
        height: '100%',
        opacity: '0',
        cursor: 'pointer'
      })

      el.append(fileInput)


    }
  }
})
<div ng-app="buttonApp">

  <div file-button>
    <button class='btn btn-success btn-large'>Select your awesome file</button>
  </div>

  <div file-button>
    <img src='https://www.google.com/images/srpr/logo3w.png' />
  </div>

</div>

7
Osiloke

Si vous obtenez des erreurs de liaison $ scope, veillez à envelopper le code de l'événement click sur une fonction setTimeout.

VUE

<input id="upload"
    type="file"
    ng-file-select="onFileSelect($files)"
    style="display: none;">

<button type="button"
    ng-click="clickUpload()">Upload</button>

MANETTE

$scope.clickUpload = function(){
    setTimeout(function () {
      angular.element('#upload').trigger('click');
    }, 0);
};
3
Rick

Il suffit de les placer dans le même contrôleur et de faire quelque chose comme ceci:

HTML:

<input id="upload"
    type="file"
    ng-file-select="onFileSelect($files)"
    style="display: none;">

<button type="button"
    ng-click="startUpload()">Upload</button>

JS:

var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
  $scope.files = [];
  $scope.startUpload = function(){
    for (var i = 0; i < $scope.files.length; i++) {
      $upload($scope.files[i]);
    } 
  }
  $scope.onFileSelect = function($files) {
     $scope.files = $files;
  };
}];

C’est, à mon avis, le meilleur moyen de le faire en angulaire. Utiliser jQuery pour rechercher l'élément et déclencher un événement n'est pas la meilleure pratique.

1
Mosho

Je viens de rencontrer ce problème et ai écrit une solution pour ceux qui utilisent Angular. Vous pouvez écrire une directive personnalisée composée d'un conteneur, d'un bouton et d'un élément d'entrée avec un fichier type. Avec CSS, vous placez ensuite l'entrée sur le bouton personnalisé, mais avec l'opacité 0. Vous définissez la hauteur et la largeur du conteneur sur exactement la largeur et la hauteur du décalage du bouton et la hauteur et la largeur de l'entrée sur 100% du conteneur.

la directive

angular.module('myCoolApp')
  .directive('fileButton', function () {
    return {
      templateUrl: 'components/directives/fileButton/fileButton.html',
      restrict: 'E',
      link: function (scope, element, attributes) {

        var container = angular.element('.file-upload-container');
        var button = angular.element('.file-upload-button');

        container.css({
            position: 'relative',
            overflow: 'hidden',
            width: button.offsetWidth,
            height: button.offsetHeight
        })

      }

    };
  });

un modèle de jade si vous utilisez du jade

div(class="file-upload-container") 
    button(class="file-upload-button") +
    input#file-upload(class="file-upload-input", type='file', onchange="doSomethingWhenFileIsSelected()")  

le même modèle en html si vous utilisez html

<div class="file-upload-container">
   <button class="file-upload-button"></button>
   <input class="file-upload-input" id="file-upload" type="file" onchange="doSomethingWhenFileIsSelected()" /> 
</div>

le css

.file-upload-button {
    margin-top: 40px;
    padding: 30px;
    border: 1px solid black;
    height: 100px;
    width: 100px;
    background: transparent;
    font-size: 66px;
    padding-top: 0px;
    border-radius: 5px;
    border: 2px solid rgb(255, 228, 0); 
    color: rgb(255, 228, 0);
}
.file-upload-input {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
}
1
Benjamin Conant

Une autre directive 

html

<btn-file-selector/>

code

.directive('btnFileSelector',[function(){
  return {
    restrict: 'AE', 
    template: '<div></div>', 
    link: function(s,e,a){

      var el = angular.element(e);
      var button = angular.element('<button type="button" class="btn btn-default btn-upload">Add File</button>'); 
      var fileForm = angular.element('<input type="file" style="display:none;"/>'); 

      fileForm.on('change', function(){
         // Actions after the file is selected
         console.log( fileForm[0].files[0].name );
      });

      button.bind('click',function(){
        fileForm.click();
      });     


     el.append(fileForm);
     el.append(button);
    }
  }  
}]); 
0

La solution, comme le soulignent d’autres réponses, consiste à utiliser

angular.element(element).trigger(event);

Voici un exemple de sélection aléatoire de plusieurs éléments select:

$scope.randomize = function(){
    var games = [].slice.call(document.querySelectorAll('.games select'));

    games.forEach(function(e){
        // Logically change the element (Angular won't know about this)
        e.selectedIndex = parseInt(Math.random() * 100, 10) < 50 ? 1 : 2;

        // Manually tell Angular that the DOM has changed
        angular.element(e).trigger('change');
    });
};
0
rodrigo-silveira

J'ai pris la réponse postée par Osiloke (qui était le plus simple et le plus complet à mon humble avis) et j'ai ajouté un auditeur d'événement de changement. Fonctionne très bien! Merci Osiloke. Voir ci-dessous si vous êtes intéressé:

HTML:

  <div file-button>
        <button class='btn btn-success btn-large'>Select your awesome file</button>
   </div>

Directif:

app.directive('fileButton', function() {
  return {
    link: function(scope, element, attributes) {

      var el = angular.element(element)
      var button = el.children()[0]

      el.css({
        position: 'relative',
        overflow: 'hidden',
        width: button.offsetWidth,
        height: button.offsetHeight
      })

      var fileInput = angular.element('<input id='+scope.file_button_id+' type="file" multiple />')
      fileInput.css({
        position: 'absolute',
        top: 0,
        left: 0,
        'z-index': '2',
        width: '100%',
        height: '100%',
        opacity: '0',
        cursor: 'pointer'
      })

      el.append(fileInput)
      document.getElementById(scope.file_button_id).addEventListener('change', scope.file_button_open, false); 
    }
  }
});

Manette:

$scope.file_button_id = "wo_files";    
$scope.file_button_open = function() 
{
  alert("Files are ready!");
}
0
Tony