angularjs upload file using components - angularjs

I am trying to upload file using angular component structure but i am not able to get the selected files.
Step 1:Template data.
<form name="form">
Hello {{vm.name}} <br />
Upload: <input my-directive type="file" name="file" ng-model="files" /> <br />
<input type="button" ng-click='vm.uploadFile()' value="Upload File." />
</form>
Step 2: Js file combined looks like
'use strict';
angular.module('app', ['ngFileUpload']);
class TestController {
constructor(){
this.name = 'user';
}
getFiles(selectedFiles){
console.log('Selected files are : ' + JSON.stringify(selectedFiles));
this.files = selectedFiles; // results empty data.
}
uploadFile (){
console.log('Model data i.e. files consists of : ' + JSON.stringify(this.files));
// Upload code will do later.
}
}
angular.module('app').directive('myDirective', function () {
return {
restrict: 'A',
scope: true,
link: function (scope, element, attr) {
element.bind('change', function () {
console.log('Value of element is :' + JSON.stringify(element[0].files[0]));
});
}
};
});
//Created a test controller here.
angular.module('app').controller('TestController', TestController);
// Created a component here.
angular.module('app').component('test', {
templateUrl: 'test.html',
controller: TestController,
controllerAs : 'vm',
});
Thanks in Advance, well i am new to angular :)

Sorry, I didn't notice that you were using typescript. I'm not really up to speed on ts at all yet. I answered a somewhat similar question that I can't find right now the other day with the code below. Note that there's an issue with ng-model and the file input type, so it uses document.getElementById to figure out the file. I suspect that this issue is what you're running into.
<html>
<body>
<form name="form" ng-app="app" ng-controller="Ctrl as ctrl">
Upload file:
<input type="file" id="file" ng-model="ctrl.file" />
<br/>
<br/> Enter text:
<textarea id="textarea" ng-model="ctrl.text"></textarea>
<br/>
<br/>
<button class="btn btn-primary btn-large" ng-click="ctrl.submitForm()">Submit</button>
</form>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js">
</script>
<script>
angular.module('app', []).controller('Ctrl', function() {
var vm = this;
vm.file = ""
vm.text = ""
vm.submitForm = function() {
// angular doesn't update the model for input type="file"
vm.file = document.getElementById('file').value;
var retVal = false ;
alert(vm.file);
alert(vm.text);
if (vm.file && ! vm.text)
{retVal = true}
else if (vm.text && ! vm.file)
{retVal = true}
else if (!vm.text && !vm.file)
{retVal = false}
else if (vm.text && vm.file)
{retVal = false}
if (!retVal) {
alert("Please specify either a file or text, not both!")
} else
alert("ok")
}
});
</script>
</html>

Related

How to trigger element click on angular js?

I have an input file and it is hidden. I want to trigger the input file once the button is clicked but my code is not working. What changes does it need to make it work?
HTML:
<input type="file" ng-model="data.file" id="upload" style="display:none;">
<button type="button" ng-click="browseFile()">Choose a file</button>
JavaScript:
$scope.browseFile = function () {
angular.element(document.querySelector('#upload')).triggerHandler('click');
}
In html use something like below
<img id="preview_image" src="" accept="image/*" class="upload_img" alt="">
<input id="image_upload" ng-model="file" type="file" class="upload_image_file" />
And in controller use $watch
$scope.$watch("file", function() {
readURL(angular.element("#image_upload")[0]);
});
function readURL(input) {
if (input && input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
angular.element("#preview_image").attr("src", e.target.result);
vm.base64File = e.target.result;
};
reader.readAsDataURL(input.files[0]);
}
}
For more info, read here and here
Update
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.file = '';
$scope.$watch("file", function() {
console.log($scope.file)
});
});
app.directive('fileModel', ['$parse', function($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function() {
scope.$apply(function() {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<label class="upload_image_label" for="image_upload">
choose file
<input id="image_upload" file-model="file" type="file" style="display:none" />
</label>
<hr> <br> File: {{file}}
</div>
</body>
</html>
As adardesign said
This is due to a security restriction.
I found out that the security restriction is only when the
<input type="file"/>
is set to display:none; or is visibility:hidden.
So i tried positioning it outside the viewport by setting
position:absolute and top:-100px; and voilĂ  it works.
You can find more in this post: Jquery trigger file input

How can I Upload two files using two different file input in Angular Js?

I am checking extension of files , using angular js , my html code is:
<input type="file" name="file" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="button" value="Click" ng-click="click()" />
and angular controller code is :
$scope.verifiedFileType = function (file) {
var fileName = file.name;
var extension = (fileName.substring(fileName.lastIndexOf('.'), fileName.length)).toLowerCase();
if (extension === ".pdf") {
return true;
}
else {
return false;
}
};
$scope.click = function () {
if ($scope.verifiedFileType($scope.SelectedFileForUpload)) {
alert("Yes");
} else {
alert("No");
}
}
This works fine. But I want to check the extension of two files of two separete file inputs. I have tried this:
<input type="file" name="file" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="file" name="file2" onchange=" angular.element(this).scope().selectFileforUpload(this.files) " required/>
<input type="button" value="Click" ng-click="click()" />
$scope.click = function () {
if ($scope.verifiedFileType($scope.SelectedFileForUpload[0]) && $scope.verifiedFileType($scope.SelectedFileForUpload[1])) {
alert("Yes");
} else {
alert("No");
}
}
But this code doesn't run. How can I perfom this task?
You can try below-given directive approach to achieve this.
Directive
app.directive('ngFileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var validFormats = ['jpg'];
element.bind('change', function () {
var values = [];
angular.forEach(element[0].files, function (item) {
var fileName = item.name;
console.log(fileName);
let ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
if(validFormats.indexOf(ext) == -1){
//Setup image upload logic here...
}
});
});
}
};
}]);
HTML
<body ng-controller="MainCtrl">
<input type="file" ng-file-model="files1" multiple />
<input type="file" ng-file-model="files" multiple />
</body>
Hope this will give you boost!

How to include input fields from custom directives in angular forms?

I need to create a simple form with validations like this - https://jsfiddle.net/rohansh20/k7omkz7p/2/
<div ng-app="module1" ng-controller="ctrl1 as vm">
<form novalidate name="vm.form1" class="css-form">
<label>Name:
<input type="text" name="Name" ng-model="vm.user.name" required />
</label>
<br />
<label>E-mail:
<input type="email" name="Email" ng-model="vm.user.email" required />
</label>
<br />
<input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
</form>
<div>
{{vm.result}}
</div>
<pre>form = {{vm.form1 | json}}</pre>
</div>
angular.module('module1', []);
angular.module('module1').controller('ctrl1', function() {
this.save = function(form, user) {
if(form.$invalid) {
this.result = 'Please correct the data entered';
return;
}
this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
};
});
But I need to dynamically generate the input fields. So I have made a directive that transforms into any type of input field - https://jsfiddle.net/rohansh20/hdxj0np6/3/
<div ng-app="module1" ng-controller="ctrl1 as vm">
<form novalidate name="vm.form1" class="css-form">
<custom-input name="Name" type="text" model="vm.user.name" required="true">
</custom-input>
<br />
<custom-input name="Email" type="email" model="vm.user.email" required="true">
</custom-input>
<br />
<input type="submit" ng-click="vm.save(vm.form1, vm.user)" value="Save" />
</form>
<div>
{{vm.result}}
</div>
<pre>form = {{vm.form1 | json}}</pre>
</div>
var app = angular.module('module1', []);
app.controller('ctrl1', function() {
this.save = function(form, user) {
if(form.$invalid) {
this.result = 'Please correct the data entered';
return;
}
this.result = 'User ' + user.name + ' with email ' + user.email + ' saved successfully';
};
});
app.directive('customInput', function($compile) {
return {
restrict: 'E',
link: function(scope, element, attributes) {
var labelElement = angular.element('<label/>'),
name = attributes.name,
type = attributes.type,
ngModelString = attributes.model,
required = attributes.required,
inputElement = angular.element('<input/>');
inputElement.attr('ng-model', ngModelString);
inputElement.attr('name', name);
inputElement.attr('type', type);
if (required) {
inputElement.attr('required', 'required');
}
labelElement.append(name + ': ');
labelElement.append(inputElement);
$compile(labelElement)(scope);
element.replaceWith(labelElement);
}
}
});
The fiddles are simplified versions of what I'm trying to make.
The problem is that these fields, even though compiled and rendered perfectly(which can be seen by inspecting the HTML), are not getting included as part of the parent form control. This can be seen in the displayed form control object in both the fiddles. Because of this, the form validity cannot be determined and both forms behave differently on submitting invalid input.
I need the form control in the second fiddle to have correct values for its properties and to have the child controls and their properties like in the first fiddle. Is this even possible using a custom directive? What do I need to change to make this work?
Note - The directive would involve complex operations to dynamically create HTML, so it has to be done in the link function of a directive. A directive template with multiple ngIfs would just not work.
In order not to lose bindings from your parent form, include it in your custom form directive
In your directive
(function () {
'use strict';
angular
.module('myApp')
.directive('customInput', customInput)
customInput.$inject = ['$compile'];
/* #ngInject */
function customInput ($compile) {
var directive = {
templateUrl: 'app/custom-input.html',
restrict: 'E',
transclude: true,
require: "?^form",
compile: compile,
controller:CustomInputController,
controllerAs:'vm',
scope:{
inputType:'=',
inputValue:'='
}
};
return directive;
function CustomInputController($scope){
var vm = this;
}
function compile(element, attributes){
return {
pre: preLink,
post: postLink
}
}
function preLink (scope,element,attrs, form, transclude){
}
function postLink (scope,element,attrs, form, transclude){
scope.currentForm = form;
$compile(element.contents())(scope);
}
}
})();
In your directive html template
<input type="inputType" ng-model="inputValue">
When you call your directive
<br-input type="text"
input-value="vm.user.email"
inputname="name"
input-required ="true">
</br-input>

File name doesn't get cleared after form.$setPristine for a custom angular directive for file upload

I am using angular 1.5.8. After following some resources, I got the file upload working. I had to create a custom directive for that.
Directive
//file-upload-model-directive.js
'use strict';
export default function (app) {
app.directive('fileUploadModel', fileUploadModelDirective);
function fileUploadModelDirective () {
'ngInject';
return {
restrict: 'A',
link: linkFn,
require: 'ngModel'
};
function linkFn (scope, element, attrs, ngModel) {
element.bind('change', function(event){
var files = event.target.files;
var file = files[0];
ngModel.$setViewValue(file);
scope.$apply();
});
}
}
}
I am also using angular's form. And I have a "reset" button on this form. I want to clear all the form fields when clicked. And it happens with all form fields except file.
View
<form ng-submit="dataCtrl.upload(form)" name="form">
<div class="form-group" ng-class="{'has-error' : form.file.$invalid && !form.file.$pristine}">
<label>Select file</label>
<input type="file" name="file" ng-model="dataCtrl.newUpload.csvFile" file-upload-model required/>
</div>
<div class="form-group" ng-class="{'has-error' : form.comment.$invalid && !form.comment.$pristine}">
<label>Comment</label>
<textarea class="form-control" name="comment"
ng-model="dataCtrl.newUpload.comment" required></textarea>
</div>
<div class="form-group pull-right">
<button type="submit" class="btn btn-success" ng-disabled="form.$invalid">Upload</button>
<button class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty">Reset</button>
</div>
</form>
And the Controller
'use strict';
function DataController($log, catalogCnst, requestSV, $http) {
'ngInject';
this.reset = function(form) {
this.newUpload = {};
// form.file.$setViewValue(null); // this didn't work either
form.$setPristine()
};
this.upload = function(form) {
// some code
};
}
When "reset" is clicked, I see that
form.file.$pristine is false
form.file.$invalid is false
But I still see filename near the file upload element.
I also tried adding watch and handling event on the element in the directive
scope.$watch(attrs.fileUploadModel, function(value) {
console.log('attrs.file');
});
element.on('$pristine', function() {
console.log('destroy');
});
But they didn't get invoked.
How do I do this? Please guide me.
When you clear newUpload, file input does not get cleared. You need to do this separately.
See JSFiddle:
Basically, I added to the directive scope:
scope: {
model: '=ngModel'
},
... and watch:
scope.$watch('model', function(file) {
if (!file) {
element.val('');
}
});
Instead of using button tags, why not use input tags. This, in theory, might work.
<input type="submit" class="btn btn-success" ng-disabled="form.$invalid" value="Upload">
<input type="reset" class="btn btn-default" ng-click="dataCtrl.reset(form)" ng-disabled="!form.$dirty" value="Reset">

How to validate forms with dynamic ngMessages

This plunk has a form with a field that only allows to enter aaa. Note that the error message is set in the controller, not in the html. When the user clicks on Submit they should see the message, but the message is not shown. What's wrong with this code?
HTML
<body ng-app="ngMessagesExample" ng-controller="ctl">
<form name="myForm" novalidate ng-submit="submitForm()">
<label>
This field is only valid when 'aaa' is
<input type="field1"
ng-model="data.field1"
name="field1"
required />
</label>
<div ng-messages="myForm.field1.$error" style="color:red">
<div ng-message-exp="required">{{errorMsg}}</div>
</div>
<br/><br/>
<button style="float:left" type="submit">Submit</button>
</form>
</body>
Javascript
var app = angular.module('ngMessagesExample', ['ngMessages']);
app.controller('ctl', function ($scope) {
$scope.submitForm = function() {
if ($scope.field1 != 'aaa')
$errorMsg = "This field should be 'aaa'";
else
$errorMsg = "";
};
});
Forget my previous answer.
Easiest and most robust is actually to make a new directive.
var app = angular.module('ngMessagesExample', ['ngMessages']);
app.directive("aaa", function() {
return {
restrict: "A",
require: "ngModel",
link: function(scope, element, attributes, ngModel) {
ngModel.$validators.aaa = function(modelValue) {
return modelValue === 'aaa';
}
}
};
});
And your controller:
app.controller('ctl', function ($scope) {
$scope.data = {
field1: ""
}
$scope.submitForm = function(){
//extra whatever code
}
});
Your HTML should be this:
<body ng-app="ngMessagesExample" ng-controller="ctl">
<form name="myForm" novalidate ng-submit="submitForm(myForm)">
<label>This field is only valid when 'aaa' is</label>
<input type="field1"
ng-model="data.field1"
name="field1"
required aaa/>
<div ng-messages="myForm.field1.$error" style="color:red">
<div ng-message="required">FIELD IS REQUIRED!!</div>
<div ng-message="aaa">FIELD MUST BE 'aaa'</div>
</div>
<button style="float:left" type="submit">Submit</button>
</form>
</body>

Resources