Я новичок в angular. Я пытаюсь прочитать загруженный путь к файлу из поля "файл" HTML всякий раз, когда в этом поле происходит "изменение". Если я использую 'onChange', он работает, но когда я использую его angular, используя 'ng-change', он не работает.
<script>
var DemoModule = angular.module("Demo",[]);
DemoModule .controller("form-cntlr",function($scope){
$scope.selectFile = function()
{
$("#file").click();
}
$scope.fileNameChaged = function()
{
alert("select file");
}
});
</script>
<div ng-controller="form-cntlr">
<form>
<button ng-click="selectFile()">Upload Your File</button>
<input type="file" style="display:none"
id="file" name='file' ng-Change="fileNameChaged()"/>
</form>
</div>
fileNameChaged() никогда не вызывает. Firebug также не показывает никаких ошибок.
Отсутствует поддержка привязки для управления загрузкой файлов
https://github.com/angular/angular.js/issues/1375
<div ng-controller="form-cntlr">
<form>
<button ng-click="selectFile()">Upload Your File</button>
<input type="file" style="display:none"
id="file" name='file' onchange="angular.element(this).scope().fileNameChanged(this)" />
</form>
</div>
вместо
<input type="file" style="display:none"
id="file" name='file' ng-Change="fileNameChanged()" />
можете попробовать
<input type="file" style="display:none"
id="file" name='file' onchange="angular.element(this).scope().fileNameChanged()" />
Примечание. Для этого требуется, чтобы приложение angular всегда находилось в режиме отладки. Это не будет работать в производственном коде, если режим отладки отключен.
и в вашей функции изменения вместо
$scope.fileNameChanged = function() {
alert("select file");
}
можете попробовать
$scope.fileNameChanged = function() {
console.log("select file");
}
Ниже приведен один рабочий пример загрузки файла с загрузкой файла перетаскивания. Может оказаться полезным http://jsfiddle.net/danielzen/utp7j/
Angular Информация о загрузке файлов
URL для загрузки файла AngularJS в ASP.Net
http://cgeers.com/2013/05/03/angularjs-file-upload/
Загрузка нескольких файлов с несколькими файлами AngularJs с помощью NodeJS
http://jasonturim.wordpress.com/2013/09/12/angularjs-native-multi-file-upload-with-progress/
ngUpload - служба AngularJS для загрузки файлов с использованием iframe
Я сделал небольшую директиву для прослушивания изменений ввода файла.
view.html:
<input type="file" custom-on-change="uploadFile">
controller.js:
app.controller('myCtrl', function($scope){
$scope.uploadFile = function(event){
var files = event.target.files;
};
});
directive.js:
app.directive('customOnChange', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var onChangeHandler = scope.$eval(attrs.customOnChange);
element.on('change', onChangeHandler);
element.on('$destroy', function() {
element.off();
});
}
};
});
Это уточнение некоторых из других, данные будут в конечном итоге в ng-модели, которая обычно вам нужна.
Разметка (просто создайте файл данных атрибута, чтобы директива могла его найти)
<input
data-file
id="id_image" name="image"
ng-model="my_image_model" type="file">
JS
app.directive('file', function() {
return {
require:"ngModel",
restrict: 'A',
link: function($scope, el, attrs, ngModel){
el.bind('change', function(event){
var files = event.target.files;
var file = files[0];
ngModel.$setViewValue(file);
$scope.$apply();
});
}
};
});
$scope.$apply();
требуется? Кажется, что мое событие ng-change
все еще происходит без него.
Чистым способом является создание собственной директивы для привязки к событию "change". Просто чтобы вы знали, что IE9 не поддерживает FormData, поэтому вы не можете реально получить объект файл из события изменения.
Вы можете использовать ng-file-upload библиотеку, которая уже поддерживает IE с FileAPI polyfill и упрощает отправку файла на сервер. Он использует директиву для достижения этого.
<script src="angular.min.js"></script>
<script src="ng-file-upload.js"></script>
<div ng-controller="MyCtrl">
<input type="file" ngf-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['ngFileUpload']);
var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
Upload.upload({
url: 'my/upload/url',
data: {file: $file}
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
}
}];
Я расширил идею @Stuart Axon, чтобы добавить двустороннюю привязку для ввода файла (т.е. разрешить сброс ввода путем сброса значения модели обратно до нуля):
app.directive('bindFile', [function () {
return {
require: "ngModel",
restrict: 'A',
link: function ($scope, el, attrs, ngModel) {
el.bind('change', function (event) {
ngModel.$setViewValue(event.target.files[0]);
$scope.$apply();
});
$scope.$watch(function () {
return ngModel.$viewValue;
}, function (value) {
if (!value) {
el.val("");
}
});
}
};
}]);
data-ng-click="vm.theFile=''"
работает хорошо, нет необходимости записывать его в метод контроллера
Как и некоторые другие хорошие ответы здесь, я написал директиву для решения этой проблемы, но эта реализация более точно отражает способ angular привязки событий.
Вы можете использовать следующую директиву:
HTML
<input type="file" file-change="yourHandler($event, files)" />
Как вы можете видеть, вы можете вставлять файлы, выбранные в обработчик событий, так как вы добавляете объект $event в любой обработчик событий ng.
Javascript
angular
.module('yourModule')
.directive('fileChange', ['$parse', function($parse) {
return {
require: 'ngModel',
restrict: 'A',
link: function ($scope, element, attrs, ngModel) {
// Get the function provided in the file-change attribute.
// Note the attribute has become an angular expression,
// which is what we are parsing. The provided handler is
// wrapped up in an outer function (attrHandler) - we'll
// call the provided event handler inside the handler()
// function below.
var attrHandler = $parse(attrs['fileChange']);
// This is a wrapper handler which will be attached to the
// HTML change event.
var handler = function (e) {
$scope.$apply(function () {
// Execute the provided handler in the directive scope.
// The files variable will be available for consumption
// by the event handler.
attrHandler($scope, { $event: e, files: e.target.files });
});
};
// Attach the handler to the HTML change event
element[0].addEventListener('change', handler, false);
}
};
}]);
fileChange
? Я использую эту директиву внутри ng-repeat
и переменная $scope
передаваемая в attrHandler
одинакова для каждой записи. Какое лучшее решение?
Эта директива также передает выбранные файлы:
/**
*File Input - custom call when the file has changed
*/
.directive('onFileChange', function() {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var onChangeHandler = scope.$eval(attrs.onFileChange);
element.bind('change', function() {
scope.$apply(function() {
var files = element[0].files;
if (files) {
onChangeHandler(files);
}
});
});
}
};
});
HTML, как его использовать:
<input type="file" ng-model="file" on-file-change="onFilesSelected">
В моем контроллере:
$scope.onFilesSelected = function(files) {
console.log("files - " + files);
};
Я рекомендую создать директиву
<input type="file" custom-on-change handler="functionToBeCalled(params)">
app.directive('customOnChange', [function() {
'use strict';
return {
restrict: "A",
scope: {
handler: '&'
},
link: function(scope, element){
element.change(function(event){
scope.$apply(function(){
var params = {event: event, el: element};
scope.handler({params: params});
});
});
}
};
}]);
эта директива может использоваться много раз, она использует свою собственную область действия и не зависит от родительской области. Вы также можете дать некоторые параметры функции обработчика. Функция обработчика будет вызвана с объектом scope, который был активен при изменении ввода. $ применяются обновления вашей модели каждый раз, когда событие изменения называется
Самая простая версия Angular jqLite.
JS:
.directive('cOnChange', function() {
'use strict';
return {
restrict: "A",
scope : {
cOnChange: '&'
},
link: function (scope, element) {
element.on('change', function () {
scope.cOnChange();
});
}
};
});
HTML:
<input type="file" data-c-on-change="your.functionName()">
Angular (например, корневой элемент директивы) являются объектами jQuery [Lite]. Это означает, что мы можем зарегистрировать прослушиватель событий так:
link($scope, $el) {
const fileInputSelector = '.my-file-input'
function setFile() {
// access file via $el.find(fileInputSelector).get(0).files[0]
}
$el.on('change', fileInputSelector, setFile)
}
Это событие события jQuery. Здесь слушатель присоединяется к корневому элементу директивы. Когда событие будет запущено, оно будет пузыриться до зарегистрированного элемента, и jQuery определит, возникло ли событие от внутреннего элемента, соответствующего определенному селектору. Если это произойдет, обработчик будет срабатывать.
Преимущества этого метода:
ng-if
или ng-switch
)ng-change
1Чтобы создать элемент <input type=file>
, выполните директиву ng-change, ему потребуется настраиваемая директива, которая работает с директивой ng-model.
<input type="file" files-input ng-model="fileList"
ng-change="onInputChange()" multiple />
angular.module("app",[])
.directive("filesInput", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
})
.controller("ctrl", function($scope) {
$scope.onInputChange = function() {
console.log("input change");
};
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app" ng-controller="ctrl">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" files-input ng-model="fileList"
ng-change="onInputChange()" multiple />
<h2>Files</h2>
<div ng-repeat="file in fileList">
{{file.name}}
</div>
</body>
Другим интересным способом прослушивания изменений ввода файла является просмотр атрибута ng-model входного файла. Off course FileModel - это настраиваемая директива.
Вот так:
HTML → <input type="file" file-model="change.fnEvidence">
Код JS →
$scope.$watch('change.fnEvidence', function() {
alert("has changed");
});
Надеюсь, это поможет кому-то.
Я сделал это вот так:
<!-- HTML -->
<button id="uploadFileButton" class="btn btn-info" ng-click="vm.upload()">
<span class="fa fa-paperclip"></span></button>
<input type="file" id="txtUploadFile" name="fileInput" style="display: none;" />
// self is the instance of $scope or this
self.upload = function () {
var ctrl = angular.element("#txtUploadFile");
ctrl.on('change', fileNameChanged);
ctrl.click();
}
function fileNameChanged(e) {
console.log(self.currentItem);
alert("select file");
}
Слишком полная база решений:
`onchange="angular.element(this).scope().UpLoadFile(this.files)"`
Простой способ скрыть поле ввода и заменить его изображением, здесь после решения, которое также требует взломать angular, но выполняющего задание [TriggerEvent не работает должным образом]
Решение:
При щелчке изображения имитируется действие DOM 'click' в поле ввода. Et voilà!
var tmpl = '<input type="file" id="{{name}}-filein"' +
'onchange="angular.element(this).scope().UpLoadFile(this.files)"' +
' multiple accept="{{mime}}/*" style="display:none" placeholder="{{placeholder}}">'+
' <img id="{{name}}-img" src="{{icon}}" ng-click="clicked()">' +
'';
// Image was clicked let simulate an input (file) click
scope.inputElem = elem.find('input'); // find input in directive
scope.clicked = function () {
console.log ('Image clicked');
scope.inputElem[0].click(); // Warning Angular TriggerEvent does not work!!!
};