0

I have a working example using standard Javascript, but I'd like to make this work more natively with AngularJS.

Specifically, I need to update the span with the filename of the file selected by the user.

Here's what I implemented using native Javascript:

<span>
    <input  ng-model="uploadDownloads" type="file" style="visibility:hidden; width: 1px;" id=uploadDownloads name=uploadDownloads onchange="$(this).parent().find('span').html($(this).val().replace('C:\\fakepath\\', ''))"  /> <!-- Chrome security returns 'C:\fakepath\'  -->
    <input  class="btn btn-primary" type="button" value="choose file" onclick="$(this).parent().find('input[type=file]').click();"/> <!-- on button click fire the file click event -->
    <span  class="badge badge-important" ></span>
</span> 

The filereader function is in angular already :

$scope.add = function(valid){
        if(valid){
                $scope.data = 'none';
                var f = document.getElementById('uploadDownloads').files[0];
                var r = new FileReader();
                r.onloadend = function(e){
                    $scope.data = e.target.result;
                    $scope.notPass = false;
                    $modalInstance.close({
                        'data':$scope.data,
                        'fileName':$scope.fileName,
                        'fileExplain':$scope.fileExplain
                    });
                };
            /*activate the onloadend to catch the file*/
                r.readAsBinaryString(f);
        } else {
            $scope.notPass = true;
        }
    };

The problem is to activate the onclick and the onchange with Angular instead the JavaScript so that my <span> gets updated with the selected filename.

13
  • What's the exact question here? Also, your code isn't very idiomatic of AngularJS. You ought to look into using ng-change and ng-click. Also, if you're modifying the DOM, you ought to consider using a directive. Commented Nov 28, 2015 at 15:43
  • i want to make the same thing that here but with angular Commented Nov 28, 2015 at 15:45
  • Ok, I understand now. Have you looked at this stackoverflow question and answer? stackoverflow.com/questions/18571001/… Commented Nov 28, 2015 at 15:50
  • its not the upload that i cant do, its to add the file name to the span Commented Nov 28, 2015 at 15:56
  • Have you looked at this article?: stackoverflow.com/questions/17213526/… Commented Nov 28, 2015 at 16:15

1 Answer 1

1

This question builds upon an existing question and answer. Specifically, however, I have modified the code from that answer to accomodate what appears to be the specific question here, which is how do you update a <span> to have the filename selected by a user in a way that's idiomatic to angularjs.

Here's a codepen with a working sample.

Here's the relevant part of the html file:

<body ng-controller="AppController">
    <input ng-model="uploadDownloads" type="file" fd-input file-name="fileName"/> 
    <span class="badge badge-important">Output here: {{fileName}}</span>
</body>

What's key here is that you have a custom directive called fd-input that has a two-way binding to an attribute it defines called file-name. You can pass one of your $scope variables into that attribute and the directive will bind the filename to it. Here's the controller and the directive.

(function() {
  'use strict';

  angular.module('app', [])
    .controller('AppController', AppController)
    .directive('fdInput', fdInput);

  function AppController($scope) {
    $scope.fileName = '';
  }

  function fdInput() {
    return {
      scope: {
        fileName: '='
      },
      link: function(scope, element, attrs) {
        element.on('change', function(evt) {
          var files = evt.target.files;
          console.log(files[0].name);
          console.log(files[0].size);

          scope.fileName = files[0].name;
          scope.$apply();
        });
      }
    }
  };

})();

As mentioned above, the directive is taken directly from another SO answer. I have modified it to add a scope that does a two way binding to a file-name attribute:

...
return {
  scope: {
    fileName: '='
  },
...

I then assign files[0].name to the two-way binding:

...
scope.fileName = files[0].name;
scope.$apply();
...

Checkout the codepen. That should do it. You could just use the parent scope in the directive, but that's not a good idea as it limits you to using this directive once per controller. Also, if you want to list multiple files, you'll have to update this code to return an array of those files instead.

Hope this help.

Sign up to request clarification or add additional context in comments.

4 Comments

ok, so i added it to my html code and my angular controller, and it didnt worked. but when i tried it in some test.html and test.js it worked. i think that it may not work because i use it in a angular-ui modal . it does upload the file , but doesn't show the name, i think for some reason it doesn't triggers the directive.
Unfortunately, that's a different question that strays from the context of this question. My suggestion would be that this answer solves your problem (if the solution is working in isolation), and you should proceed by searching Stackoverflow for a solution to properly sharing your $scope with your angular-ui modal. You're almost there! :) If you don't mind, mark this answered so that it doesn't show up as unanswered when the community is searching around for questions to answer. Good luck!
for what is the :file-name="fileName" in the < input > ?
Read the directives documentation: (docs.angularjs.org/guide/directive) - in the directive there's a property scope in the returned object that has an object with the property fileName: '=' - that creates an attribute that supports two-way binding. You pass a $scope.whatever property into that attribute, which the directive then binds the results to (scope.fileName = files[0].name;)... if you pass $scope.test into the file-name attribute, the directive binds files[0].name to $scope.test. The scope.$apply() then triggers a digest cycle so things update in your view.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.