Ember.js file upload - file-upload

I am a newbie and tried to do the laziest way to do a file upload using emberjs, jquery and formdata(IE10+). The code might look stupid, but it worked.
Here is what i got. Can you please take a look and give some suggestions. Am i doing it wrong?
<script type="text/x-handlebars" data-template-name="posts">
<form role="form" enctype="multipart/form-data" method="post" id="fileinfo" {{action 'createPost' on='submit'}}>
{{input type="text" value=newPost id="newPost" placeholder="Post" class="form-control"}}
{{input type="file" id="inputFile" class="form-control" name="file"}}
<button type="submit" class="btn btn-default" >Submit</button>
</form>
</script>
App.PostsController = Ember.ArrayController.extend({
actions: {
createPost: function(){
var fd = new FormData(document.getElementById("fileinfo"));
fd.append("postContent", this.get('newPost'));
this.set('newPost', ''); //reset text field
$('#inputFile').val(''); //reset fileinput field
Ember.$.ajax({
url: "http://localhost:3000/posts",
type: "POST",
data: fd,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
});
}
}
});

Related

How can I Upload files and JSON data in the same request with AlpineJS

I need to Add data & image file in a same post request using alpine js.
I think it is a little bit late. But, someone else might need take benefit from this answer in the future.
You can use Javascript's FormData to handle both data and file.
Bellow, I am copying a part from my application to show the full process of actually uploading image with Alpine JS and sending it as part of Form Data to your API end.
HTML Part:
<form method="post" enctype="multipart/form-data" #submit.prevent="$store.app.submitData()">
<div class="row mb-4">
<div class="form-group col-md-4">
<label>App Name</label>
<input type="text" name="name" class="form-control" x-model="$store.app.form.name">
</div>
<div class="form-group col-md-4">
<label>Slug</label>
<input type="text" name="name" class="form-control" x-model="$store.app.form.slug">
</div>
<div class="form-group col-md-4">
<label>Icon/Logo</label>
<input type="file" name="image_icon" class="form-control" x-on:change="$store.app.selectFile($event)" accept="image/png, image/jpg, image/jpeg">
</div>
</div>
<div class="row">
<div class="col-md-12 text-end mt-3">
<button type="submit" class="btn btn-lg btn-primary mb-5" :disabled="$store.app.loading">
<span class="indicator-label">Save</span>
</button>
</div>
</div>
</form>
Alpine JS Part:
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('app', {
loading: false,
form: {
name: '',
image_icon: '',
slug: ''
},
selectFile(event) {
this.form.image_icon = event.target.files[0]
},
submitData() {
//Create an instance of FormData
const data = new FormData()
let url = '/application'
// Append the form object data by mapping through them
Object.keys(this.form).map((key, index) => {
data.append(key, this. Form[key])
});
this.loading = true
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
body: data
})
.then(response => {
//...
})
.finally(() => {
this. Loading = false
});
}
})
})
</script>
Please note that I have used store in this example, you can use Alpine Data, function or inline x-data as you please.
Appending to the form data just requires a key and value pair, for example;
const data = new FormData();
data.append('name', 'John');
data.append('surname', 'Doe');
I hope this helps.

Upload file using angular material 5

I tried to upload file (angular 5) using angular material 5.
app.component.html
<mat-horizontal-stepper [linear]="isLinear" #stepper="matHorizontalStepper">
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Upload your audio file</ng-template>
<mat-form-field>
<input matInput
style="display: none"
type="file" (change)="onFileSelected($event)"
#fileInput name ="file" formControlName="firstCtrl" required>
<button mat-button (click)="fileInput.click()" >Select File</button>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
app.component.ts
export class AppComponent {
selectedFile: File=null;
isLinear = true;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
constructor(private _formBuilder: FormBuilder, private http: HttpClient) {}
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required]
});
}
But I got this error
ERROR Error: Input type "file" isn't supported by matInput.
knowing this code worked well without angular material. Any issue?
I had the same problem,
Try doing this,
<button mat-raised-button (click)="openInput()">Select File to Upload</button>
<input id="fileInput" hidden type="file" (change)="fileChange($event.target.files)" name="file" accept=".csv,.xlsv">
openInput(){
document.getElementById("fileInput").click();
}
What above code does is creates simply a Material button and call openInput() method which later on replaces that button to below HTML code
<input id="fileInput" hidden type="file" >
This worked for me.
Happy Coding ☻
Faster solution would be to use
https://github.com/danialfarid/ng-file-upload :
<md-button class='md-raised md-primary' id='uploadFile' ngf-multiple='true' ngf-select='upload($files, $file, $event)'
type='file'>
Upload File
else you would have to go to a custom code like this:
<label class="md-secondary md-raised md-button" md-ink-ripple for="input-file">
<span>Select File to upload</span>
</label>
<input type="file" ngf-select ng-model="input-file" name="input-file" id="input-file">
EDITED:
In your HTML:
<input #file type="file" nbButton multiple (change)="upload(file.files)" />
then in your component:
upload(files: any) {
this.yourServiceToUploadFiles.uploadFile(files).subscribe(
(response: any) => { .......})}
and then in your service:
uploadFile(files: any[]): Observable<HttpResponse<Blob>> {
if (files.length === 0) {
return;
}
const formData = new FormData();
for (const file of files) {
formData.append(file.name, file);
}
return this.http.post(`${apiUrl}/yourServiceEndPoint`, formData, {
observe: "response",
responseType: "blob"
});
}

GO button does nothing (AIML rails 5)

I have installed programr. I followed tutorial from this site http://dreamingechoes.github.io/bot/ruby/rails/conversational-bot-ruby-on-rails/
bot.rb
require 'programr'
brains = Dir.glob("lib/bot/*")
BOT = ProgramR::Facade.new
BOT.learn(brains)
application_controller.rb
def ask_bot
reaction = BOT.get_reaction(params[:query])
render json: { response: reaction.present? ? reaction : "I don't have an answer to that" }
end
bot.aiml
<?xml version="1.0" encoding="UTF-8"?>
<aiml version="1.0" xmlns="http://alicebot.org/2001/AIML-1.0.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://alicebot.org/2001/AIML-1.0.1 http://aitools.org/aiml/schema/AIML.xsd">
<category>
<pattern>Hello *</pattern>
<template>
Hey, how can I help you?
</template>
</category>
<category>
<pattern>*bye</pattern>
<template>
Always here for you!
</template>
</category>
<category>
<pattern>What payment methods do you accept?</pattern>
<template>
We accept Visa, MasterCard and American Express.
</template>
</category>
</aiml>
view:
<div class="alert alert-info">
×
<strong>Info!</strong> Type something on the text input and hit the <strong>GO</strong> button to get a response.
</div>
<div class="bs-callout bs-callout-info bot-response hide" id="callout-alerts-no-default">
<h4>Bot says:</h4>
<p id="bot-response"> </p>
</div>
<div class="row home-row">
<div class="col-lg-12">
<div class="input-group">
<input id="query" type="text" class="form-control" placeholder="Say something to the bot...">
<span class="input-group-btn">
<button id="ask" class="btn btn-default" type="button">GO</button>
</span>
</div>
</div>
</div>
application.js
$(document).ready(function(){
$('#ask').on('click', function(event) {
$.ajax({
url: '/ask_bot',
type: 'json',
method: 'get',
data: { query: $('#query').val() },
success: function(data) {
$('.bot-response').removeClass('hide');
$('#bot-response').html(data['response']);
$('#query').val('');
}
});
});
});
If i copy a pattern and paste in the form, the GO button does nothing. Please help...thanks!
Most probably what you'll have to use is the DOMContentLoaded in order to check when the DOM has finished loading, this way you can wrap the listener for the #ask button and the AJAX function, without having to modify your "requires" in the application.js file, nor to have to include them as script tags in your views.
You could try with something like:
document.addEventListener('DOMContentLoaded', function () {
...
});
And inside to put your JS code, which would remain as:
document.addEventListener('DOMContentLoaded', function () {
$('#ask').on('click', function(event) {
$.ajax({
url: '/ask_bot',
type: 'json',
method: 'get',
data: { query: $('#query').val() },
success: function(data) {
$('.bot-response').removeClass('hide');
$('#bot-response').html(data['response']);
$('#query').val('');
}
});
});
$('[data-toggle="tooltip"]').tooltip();
});
Also you could add the specific custom.js for the specific controller and action in which is being used, that's the reason of the Uncaught TypeError: Cannot read property 'getContext' of null error, because such elements barChart and barChart2 are in the back_office#index.

Dropzone inside a html form with other form fields not working

I want to add a dropzone inside an existing form but it doesn't seem to work.
When I view the console I get error throw new Error("No URL provided"). When I click upload I get no preview either - all I get is a normal file input.
<link href="../dropzone.css" rel="stylesheet">
<form action="/" enctype="multipart/form-data" method="POST">
<input type="text" id ="Username" name ="Username" />
<div class="dropzone" id="my-dropzone" name="mainFileUploader">
<div class="fallback">
<input name="file" type="file" />
</div>
</div>
<div>
<button type="submit" id="submit"> upload </button>
</div>
</form>
<script src="../jquery.min.js"></script>
<script src="../dropzone.js"></script>
<script>
$("my-dropzone").dropzone({
url: "/file/upload",
paramName: "file"
});
</script>
No url provided error is because $("my-dropzone") is wrong instead it must be $('#mydropzone')
dropzone along with other form, yes this is very much possible, you have to post the data using the URL provided in the dropzone not in the form action. That means all your form data along with the files uploaded shall be posted back to the url provided for the dropzone. A simple untested solution is as below;
<link href="../dropzone.css" rel="stylesheet">
<form action="/" enctype="multipart/form-data" method="POST">
<input type="text" id ="Username" name ="Username" />
<div class="dropzone" id="my-dropzone" name="mainFileUploader">
<div id="previewDiv></div>
<div class="fallback">
<input name="file" type="file" />
</div>
</div>
<div>
<button type="submit" id="submitForm"> upload </button>
</div>
</form>
<script src="../jquery.min.js"></script>
<script src="../dropzone.js"></script>
<script>
$("#mydropzone").dropzone({
url: "/<controller>/action/" ,
autoProcessQueue: false,
uploadMultiple: true, //if you want more than a file to be uploaded
addRemoveLinks:true,
maxFiles: 10,
previewsContainer: '#previewDiv',
init: function () {
var submitButton = document.querySelector("#submitForm");
var wrapperThis = this;
submitButton.addEventListener("click", function () {
wrapperThis.processQueue();
});
this.on("addedfile", function (file) {
// Create the remove button
var removeButton = Dropzone.createElement("<button class="yourclass"> Remove File</button>");
// Listen to the click event
removeButton.addEventListener("click", function (e) {
// Make sure the button click doesn't submit the form:
e.preventDefault();
e.stopPropagation();
// Remove the file preview.
wrapperThis.removeFile(file);
});
file.previewElement.appendChild(removeButton);
});
// Also if you want to post any additional data, you can do it here
this.on('sending', function (data, xhr, formData) {
formData.append("PKId", $("#PKId").val());
});
this.on("maxfilesexceeded", function(file) {
alert('max files exceeded');
// handle max+1 file.
});
}
});
</script>
The script where you initialize dropzone can be inside $document.ready or wrap it as a function and call when you want to initialize it.
Happy coding!!

How to upload a file using AngularJs like the traditional way

I've been tried this for days. Assuming I have a form like following:
<form ng-submit="create()" class="form-horizontal" enctype="multipart/form-data">
<div class="control-group">
<label class="control-label">name : </label>
<div class="controls">
<input type="text" class="input-xlarge" ng-model="message.title" />
</div>
</div>
<div class="control-group">
<label class="control-label">avatar : </label>
<div class="controls">
<input type="file" ng-model="message.avatar" name="message[avatar]" />
</div>
</div>
<div class="well">
<input class="btn btn-large btn-primary" type="submit" value="建立資料" />
</div>
</form>
I am using the carrierwave gem to handle the file upload behind the scene. My controller is like this:
$scope.create = function($scope.message){
var deferred = $q.defer();
$http({
method: 'POST',
url: '/resources/messages',
data: $.param({message: message}),
headers: {'Content-Type': 'multipart/form-data'}
}).
success(function(data, status, headers, config){
deferred.resolve(data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
});
return deferred.promise;
};
However it is not working. What I intend to do is create a form and upload everything like the old way, but the examples I found such as ng-upload, or like this post, or jquery file upload, they don't suit my need. Is there any example or sample code for this purpose? Thank you.
I think "like the old way" would be to not use Ajax, but I'm guessing that's not what you mean. :)
#shaunhusain's fiddle is a good example of how to use the FormData object to handle the file upload. And using this site as a reference, you can use the transformRequest to incorporate the FormData object.
Keeping your basic $http code, modify it to add the transform object:
$scope.create = function(message){
var deferred = $q.defer();
$http({
method: 'POST',
url: '/resources/messages',
data: message // your original form data,
transformRequest: formDataObject // this sends your data to the formDataObject provider that we are defining below.
headers: {'Content-Type': 'multipart/form-data'}
}).
success(function(data, status, headers, config){
deferred.resolve(data);
}).
error(function(data, status, headers, config){
deferred.reject(status);
});
return deferred.promise;
};
Create a factory that will incorporate manipulate the form data into a sendable payload. It will iterate through your form data (including uploaded file) and return a sender-friendly object:
app.factory('formDataObject', function() {
return function(data) {
var fd = new FormData();
angular.forEach(data, function(value, key) {
fd.append(key, value);
});
return fd;
};
});
I haven't tested this, but it should work out of the box.