0

I'm far from an expert on Angular, so I have to try asking a question here. I've added the possibility to upload files in may AngularJS project. I need to display the selected filename in a textbox (or preferably a read-only field) before the user submits the form. It contains a number of fields that need validation. The problem is, the selected filename never shows up. The textblock is still empty after selecting a file. I've tried the following code (Plunker: http://plnkr.co/edit/Ll3GZdpp8Tsqwvo0W1ax):

index.html:

<!DOCTYPE html>
<html ng-app="myApp">

<head lang="en">
  <meta charset="utf-8" />
  <title>Custom Plunker</title>
  <script data-require="[email protected]" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
  <link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
  <script data-require="bootstrap@*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
  <link rel="stylesheet" type="text/css" href="http://angular-ui.github.com/ng-grid/css/ng-grid.css" />
  <link rel="stylesheet" type="text/css" href="style.css" />
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
  <script type="text/javascript" src="http://angular-ui.github.com/ng-grid/lib/ng-grid.debug.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>

<body ng-controller="MyCtrl">

  <div class="row">
    <div class="col-md-12">
      <span class="btn btn-default btn-file">
              Välj fil... <input type="file" onchange=" angular.element(this).scope().setFile(this) ">
                                        </span>
      <input type="text" ng-model="organizationSettings.logotypeFileName" />
    </div>
  </div>
</body>

</html>

app.js:

var app = angular.module('myApp', []);
app.controller('MyCtrl', function($scope) {
  $scope.organizationSettings = {};

  $scope.setFile = function(element) {
    $scope.fileToUpload = element.files[0];
    console.log($scope.fileToUpload.name);
    $scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;
  };    
});

css:

.btn-file {
    position: relative;
    overflow: hidden;
}
.btn-file input[type=file] {
    position: absolute;
    top: 0;
    right: 0;
    min-width: 100%;
    min-height: 100%;
    font-size: 100px;
    text-align: right;
    filter: alpha(opacity=0);
    opacity: 0;
    outline: none;
    background: white;
    cursor: inherit;
    display: block;
}
3
  • you can not use modern version of angular? Commented May 13, 2015 at 22:59
  • What version is modern? 2.0? Commented May 14, 2015 at 8:41
  • I didnt mean most modern. 1.2 or 1.3 is ok, answers given by others works Commented May 14, 2015 at 14:28

3 Answers 3

2

The reason is you are using onchange which is an event outside of any of angular's directives.

Whenever you use an event outside of angular that changes the scope, you need to notify that a digest is needed to update the part of the view managed by that scope by using $apply

The simplest fix is to use ng-change instead of native onchange. All of angulars event handling directives will trigger $apply internally

The alternative (not best approach) would be keep the onchange and do:

$scope.setFile = function(element) {  
    $scope.fileToUpload = element.files[0];
    console.log($scope.fileToUpload.name);
    $scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;

    $scope.$apply();
}; 
Sign up to request clarification or add additional context in comments.

2 Comments

I can't get ng-change to trigger. If I just change inching into ng-change, I also get "Error: No controller: ngModel". The second solution works, why is it a bad idea?
no idea how that error comes up unless your code is outside of ng-app? As for second part...far better to keep code under on framework and let angular itself do all the data watching and is easier to test
1

You can't use ng-change for file upload because binding is not supported for file upload in angularjs., its an issue in angularjs.

In other cases while you are using ng-change(other than file upload) you have to use ng-model to make the ng-change directive work in order to trigger change based on it(so only you are getting "Error: No controller: ngModel") while using it.

The best possible solution is you manually trigger $scope.$apply() to make binding to the input model while programatically setting it.

Comments

1

I think that binding changes could be done easier, and I will explain below how to do it. By setting a ng-model to the input, it will automatically bind the input control to the variable defined in your controller's scope. Therefore, if you specify a new file, it will automatically update the model $scope.fileToUpload. This goes the other way around: any change in $scope.fileToUpload done in JS, will be reflected in the DOM.

index.html - try to replace

<input type="file" onchange=" angular.element(this).scope().setFile(this) ">

with

<input type="file" ng-model="fileToUpload">

In app.js, you could get rid of:

$scope.setFile = function(element) {
    $scope.fileToUpload = element.files[0];
    console.log($scope.fileToUpload.name);
    $scope.organizationSettings.logotypeFileName = $scope.fileToUpload.name;
  };    

1 Comment

This doesn't work. I need to get the files array from the input-tag.

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.