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.

jpoveda
  • 2,137
  • 1
  • 25
  • 34
Ariel Livshits
  • 591
  • 1
  • 7
  • 23
  • 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. – jpoveda Nov 28 '15 at 15:43
  • i want to make the same thing that here but with angular – Ariel Livshits Nov 28 '15 at 15:45
  • Ok, I understand now. Have you looked at this stackoverflow question and answer? http://stackoverflow.com/questions/18571001/file-upload-using-angularjs – jpoveda Nov 28 '15 at 15:50
  • its not the upload that i cant do, its to add the file name to the span – Ariel Livshits Nov 28 '15 at 15:56
  • Have you looked at this article?: http://stackoverflow.com/questions/17213526/show-the-inputtype-file-filename-at-directive-template – jpoveda Nov 28 '15 at 16:15
  • You might also want to look at [this article]( http://stackoverflow.com/questions/27227788/get-source-and-name-of-selected-file-with-angularjs). As I mentioned above, you probably want to do this as a custom directive (that would be the more Angular way to do it)... alternatively, use one of the existing Angularjs modules that has already solved your scenario. – jpoveda Nov 28 '15 at 16:19
  • do you know how to do this in angular : .val().replace('C:\\fakepath\\', '') – Ariel Livshits Nov 28 '15 at 16:20
  • Yes: http://stackoverflow.com/a/27228395/2305837 (see above). Your question is how to do this in an angular way. The angular way would be to use a directive. If you're not familiar with them, you can find documentation here: https://docs.angularjs.org/guide/directive. The answer linked to literally shows you how to get what you want the angular way. The part where he shows: `console.log(files[0].name);` has the value you want. As a quick (but not ideal) solution, from within the directive modify the parent scope with that value and bind that to your . Sorry if this isn't clear enough. – jpoveda Nov 28 '15 at 16:38
  • You're just trying to put the filename selected in the span, correct? – jpoveda Nov 28 '15 at 17:13
  • yes, thank you for all the great answers bur still it doesn't work – Ariel Livshits Nov 28 '15 at 17:17
  • ok - perfect, I'm writing an answer right now with a codepen to demonstrate the solution :). – jpoveda Nov 28 '15 at 17:17
  • cant wait for it ! thanks :) – Ariel Livshits Nov 28 '15 at 17:25
  • Ok... answer posted. Let me know if it answers your question by accepting it as the correct answer and upvoting it... otherwise, comment on the answer itself with any specific problems. – jpoveda Nov 28 '15 at 17:30

1 Answers1

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.

Community
  • 1
  • 1
jpoveda
  • 2,137
  • 1
  • 25
  • 34
  • 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. – Ariel Livshits Nov 28 '15 at 18:05
  • 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! – jpoveda Nov 28 '15 at 18:13
  • for what is the :file-name="fileName" in the < input > ? – Ariel Livshits Nov 28 '15 at 19:15
  • Read the directives documentation: (https://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. – jpoveda Nov 28 '15 at 23:16