AngularJs: upload mutiple files from different sources - angularjs

I am trying to upload two different files, an image and a pdf file, each from a different input as follows:
<div class="form-group" ng-class="libraries.error.img[0] ? 'has-error' : ''">
<label for="img">Image</label>
<input type="file" accept="image/*" ngf-select="" ngf-multiple="true" class="form-control" id="img" name="img" placeholder="Image" ng-model="libraries.library.img">
<p ng-if="libraries.error.img[0]" style="color: red">{{libraries.error.img[0]}}</p>
</div>
<div class="form-group" ng-class="libraries.error.document[0] ? 'has-error' : ''">
<label for="document">Document</label>
<input type="file" accept="application/pdf" ngf-select="" class="form-control" id="document" name="document" placeholder="Document" ng-model="libraries.library.document">
<p ng-if="libraries.error.document[0]" style="color: red">{{libraries.error.document[0]}}</p>
</div>
In the services file, I am sending it using the following:
store: function (library) {
console.log(library);
return Upload.upload({
url: 'api/libraries',
method: 'POST',
fields: {name: library.name, location: library.location},
file: [library.img, library.document]
});
},
But when I try to fetch the files at the server side as follows:
return $_FILES;
I keep getting:
[] No Properties
However when I change file to
file: library.img
meaning, I pass only one file, it works.
I am using ng-file-upload with AngularJS and the server side is Laravel
Any idea to solve this issue allowing both files to be sent to the server?!

I've had the same issue, and I was able to fix it by giving the JSON object for each file a different name (drawing inspiration from here). If I did not rename the objects, the server would receive the correct number of files but all of them would be identical. So if you were to apply this, your code would be:
store: function (library) {
console.log(library);
return Upload.upload({
url: 'api/libraries',
method: 'POST',
fields: {name: library.name, location: library.location},
file: [library.img, library.document]
fileFormDataName: [name1, name2]
});
},
I believe the names can be anything as long as they are unique. However, you now have to process the objects separately on your server side. I am not familiar with how you might do that in PHP, but on my Rails back-end, I can collect all of the files by their class:
files = params.values.find_all { |value| value.class == ActionDispatch::Http::UploadedFile }
Then I simply assign each file to the appropriate attribute of my model.

Related

how to catch nodejs api data in AngularJS page?

this is api code i am using and passing some parameters
app.get('/opner',function (req, res) {
res.sendFile(
path.join(__dirname, './','dist', 'index.html'),
{user: req.session.user,value1:req.session.value1}
);
});
i am serving angular with the same api.
in this case in ejs i can directly access this user and value1
with <%= user %> like this. but how to use the same in angular app
<div class="form-group">
<h4> value 1:</h4>
<textarea class="form-control" rows="8" ng-model="tx.data"></textarea>
</div>
<div class="form-group">
<h4>user:</h4>
<input class="form-control" type="text" ng-model="tx.user"/>
</div>
so i want to render this page with value1 and user values present.
so how to read and display in angular?
The node function res.sendFile is not the same as res.render.
res.render is for rendering EJS (or pug, or other pre-renderer).
res.sendFile only send file.
You cannot use the second argument of res.sendFile to send data alongside your index.html like you would do in EJS
The right way to do it would be to create another express route (like /getUser), and to send the json in this route with res.json({req.session.user,value1:req.session.value1})
You will then have to do a ajax request in Angular.
if you use Angular 1.x, I think the service name is http
for Angular 2+, the service name is HttpClient.
Once you have queryed the data, you can show it in your angular template like so:
<h4> value 1: {{tx.data}}</h4>
supposing you put your data on the $scope.tx.data object (angular 1.x) or as this.tx = {data : data, user : user} on the class of your component (angular 2+)
Like Felix says is better to make your own GET route to get the data via http request, but ifyou want to avoid that you need to use a template engine (like EJS or Pug) because Angular is loaded after template rendering.
res.render('yourPath/index.html', {user: req.session.user, value1: req.session.value1});
And in your AngularJS side you can use ng-init. EJS example:
<div class="form-group" ng-init="tx.data = '<%= value1 %>';tx.user = '<%= user %>'">
<h4> value 1:</h4>
<textarea class="form-control" rows="8" ng-model="tx.data"></textarea>
</div>
<div class="form-group">
<h4>user:</h4>
<input class="form-control" type="text" ng-model="tx.user"/>
</div>
PUG Interpolation example:
<div class="form-group" ng-init="tx.data = '!{value1}';tx.user = '!{user}">
<h4> value 1:</h4>
<textarea class="form-control" rows="8" ng-model="tx.data"></textarea>
</div>
<div class="form-group">
<h4>user:</h4>
<input class="form-control" type="text" ng-model="tx.user"/>
</div>

Upload files with Angular with a post containing other form data

I have followed countless examples (from here and other sites) that explain how you upload files from Angular to a web server. I am happy with the solution of using angular-file-upload and processing the data on the server (Node) with Multer.
What I haven't been able to find is a way to upload files from the form with a post that contains all the other controller data.
controller:
$scope.files = [];
$scope.name = "";
$scope.post = //$http post to server from service
view:
<input type="text" ng-model="name">
<input type="file">
<button ng-click="post()">Send post without page refresh</button>
Is there a way I can send the [name] and the [files] in the same post? If I send with multi part data will that be ok for [name] and [files]? Do I need to send two separate posts?
At the moment, my working example submits with a form action of 'post' and an enctype of "multipart/form-data". But I don't want the page to refresh and I want to send [name] and [files] from the scope... do I need to attach the files from the form to the scope or get the scope to pull the files from the DOM?
You can push formData to file before upload.
$scope.uploader.onBeforeUploadItem = function(fileItem) {
fileItem.formData.push({name: $scope.name});
};
Please look through the demo for complete solution :)
Plunkr
<form>
<input type="text" placeholder="Enter Name here" ng-model="newCountry.Name" />
<label>Choose 1 or more files:</label>
<input type="file" ng-files="AddnewCountryFlag($files)" multiple />
<h3>Try Uploading Image file. It will preview your image.</h3>
<div ng-repeat="item in imagesrc">
<img src="{{item.Src}}" />
<label>{{item.Size}}kB</label>
</div>
<input type="submit" value="Send Data" ng-click="AddCountry()" />

Uploading multiple files with angular-file-upload

I'm using angular-file-upload to upload images along with form data to my server. I've been able to do that successfully one image at a time.
My problem is that in my form I need to upload two images, using separate inputs (as well as send along other form data). My reasoning for using separate inputs is that one of my images is a thumbnail image and the other is a hero image. I need the ability to distinguish between them and insert the file paths for each into their respective columns in my database.
I read through this github issue that went through how to upload multiple files using the same input, but I wasn't able to find anything about uploading multiple files using different inputs. Maybe I'm misunderstanding them though.
Right now, if I try to select a header image, it only changes the value of the thumbnail image.
Here is my form:
<form>
...(other text form inputs above)...
<div class="form-group">
<label class="col-sm-2 control-label"> Teaser</label>
<div class="col-sm-8>
<input class="form-control" filestyle="" accept=".png,.gif,.jpg,.jpeg" data-button-text="Choose image" type='file' data-classbutton='btn btn-default' data-classinput="form-control inline" nv-file-select='' uploader='uploader' options="{'field': 'thumbnail_url'}"
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label"> Header Image</label>
<div class="col-sm-8>
<input class="form-control" filestyle="" accept=".png,.gif,.jpg,.jpeg" data-button-text="Choose image" type='file' data-classbutton='btn btn-default' data-classinput="form-control inline" nv-file-select='' uploader='uploader' options="{'field': 'header_url'}"
</div>
</div>
</form>
And here is how I am sending the file to my server (on the onCompleteAll callback I am sending my form data to the server):
$scope.uploader = new FileUploader({
url: '/laravel/public/admin/events/thumbnail_url/file_upload',
alias: 'files',
headers: {
// 'X-CSRF-Token': n/a
},
onBeforeUploadItem: function(item) {
/* Laravel file name alias */
item.alias = 'file';
},
onSuccessItem: function(fileItem, response, status, headers) {
$scope.newEventForm[fileItem.field] = '/laravel/public/uploads/events/' + response.filename;
},
onCompleteAll: function() {
/* Now ready to save form data */
AdminEvent.save($scope.newEventForm).$promise.then(function(response) {
$scope.events.push(response.data);
toaster.pop('success', 'Added', 'Event added successfully.');
});
}
});
I faced the same issue with ng-file-upload but I did not used angular-file-upload.
So may be this solution helpful for you.
In my app I have user profile image and background image.
where profile image input value I send with file option of ng-file-upload but it did not provide other option to send second file input value.
TO resolve that What I did
Created second file input and used that input model same as my table attribute like ng-model="user.bg_avatar" where bg_avatar is my background image attribute in rails.
Now You can get second file input value with user object(user.bg_avatar) in angular controller which we will send to rails and when rails get it save that with other user attribute.
But don,t forgot to permit this attribute.

How to send data to server from a select in a form

I have this controller:
$scope.disciplines = disciplines;
$scope.discipline = disciplines[0];
It's an array.
I have this in my form:
<form class="form-horizontal" ng-submit="submit()" method="post">
<input type="text" name="prj_title" ng-model="project.prj_title" class="form-control" id="title">
<select id="discipline" class="form-control" name="prj_discipline" ng-model="discipline" ng-options="d for d in disciplines"></select>
<input type="submit" class="btn btn-block btn-success btn-lg" value="Ansök">
</form>
And this is my post:
$scope.submit = function(){
$http({
method : 'POST',
url : '/api/project',
data : $.param($scope.project), // pass in data as strings
headers : { 'Content-Type': 'application/x-www-form-urlencoded' } // set the headers so angular passing info as form data (not request payload)
})
.success(function(data, status) {
...
}
})
};
The first input works. The server receives prj_title:.
But the select tag does not work.
name=discipline does not seem to have effect. The value is not sent to the server. Have read the docs and the name-property should be valid on the select tag. What I want is the select tag to send prj_discipline:
What am I doing wrong?
you can change your select ng-model like your input,
<select id="discipline" class="form-control" name="prj_discipline"
ng-model="project.prj_discipline" ng-options="d for d in disciplines"></select>
basically you need names only for form validation, what you were posting was $scope.project object which has no property with name prj_discipline, so if you bind your select model to project.prj_discipline it will work...

AngularJS and nested forms: Correct way of naming and declaring model

Ok, so I am creating a form like so:
<form novalidate class="simple-form" action="" name="mainForm" ng-submit="doSubmit()" method="POST">
<div ng-form name="giftForm" class="panel-body">
<input type="text"
id="x_amount"
name="x_amount"
class="form-control input-lg"
ng-model="giftForm.amount"
ng-required="true">
</div>
<div class="row">
<button type="submit" class="btn" ng-disabled="mainForm.$invalid">Submit</button>
</div>
</form>
This works for validation, i.e. that mainForm.$invalid only highlights enables the button after the input has text. However, using batarang, I noticed that the scope looks like so:
{"giftForm":{"x_amount":{},"amount":"a"}}
So it is creating model values based on the name and the declared ng-model. If I change them to be the same like so:
<input type="text"
id="x_amount"
name="x_amount"
class="form-control input-lg"
ng-model="giftForm.x_amount"
ng-required="true">
The submit shows the correct scope of:
{"giftForm":{"x_amount":"a"}}
But the input field initially shows with [Object object] in the input, which makes me think I am confusing something here..... I can't have that in all of the input fields.
I'd like the name and the model to be the same. That would seem to be the progressive enhancement way and would allow a normal non-ajax post by simply removing the ng-submit method and the ajax way would look like:
$http({
method : 'POST',
url : 'formAction.do',
data : $.param(angular.toJson($scope.mainForm)),
headers : { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.success(function(data) {
//success
})
.error(function(data, status, headers, config) {
//error
});
Anybody has insight into what I am missing or if my architecture is flawed from the ground-up, I'd appreciate the wisdom....
I'd like the name and the model to be the same.
You could do that, but you'd have to have a separate scope, and therefor a separate controller for your form.
More importantly, though, this isn't going to buy you anything. The input name attributes are primarily used for validation display, and not much else.
Your use of $http concerns me more. It looks like you're thinking in a JQuery mindset. I'd challenge you to throw JQuery out the window for a while until you get used to Angular.
Here's what people generally do with forms (From the model structure to the naming and validation):
View:
<form name="myForm" ng-submit="sendFoo()">
<div>
<label for="name">name</label>
<input type="text" id="name" name="name" ng-model="foo.name" required/>
<span ng-show="myForm.name.$error.required">required</span>
</div>
<div>
<label for="email">email</label>
<input type="email" id="email" name="email" ng-model="foo.email" required/>
<span ng-show="myForm.email.$error.required">required</span>
<span ng-show="myForm.email.$error.email">invalid email</span>
</div>
<button type="submit" ng-disabled="myForm.$invalid">Submit</div>
</form>
Controller:
app.controller('MyCtrl', function($scope, $http) {
$scope.foo = {
name: 'Someone Special',
email: 'test#monkey.com'
};
$scope.sendFoo = function (){
$http.post('/Some/Url/Here', $scope.foo)
.then(function(result) {
$scope.result = result.data;
});
});
});
You'll notice that the name of the form and the names of the inputs are only used for validation on those <span> tags. Like so: <span ng-show="[formName].[fieldName].$error.[validationName]">invalid message</span>. That object is available on the $scope at $scope.formName, but there usually isn't a reason to access it directly in your controller.
I hope this helps you (or someone).
Naming a form places a variable in scope with that name. Under it, it puts properties named after the form fields names. However, you already have a model in the scope with the same name as the form: giftForm. This causes confusion: the template overwrites the model and/or vice versa.
So, give another name to one of them, eg name the model giftModel.

Resources