Reputation: 2095
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;
}
Upvotes: 0
Views: 1319
Reputation: 1029
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.
Upvotes: 1
Reputation: 267
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;
};
Upvotes: 1
Reputation: 171679
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();
};
Upvotes: 2