How to upload a file using AngularJs like the traditional way - file-upload

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.

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.

Push and Insert at a time in Vuejs and PHP

I want to push the value in Array. It will show the value instantly. There is no need to refresh the whole page.
app.todoList.push(this.todo)
With this line I am doing that.
At the same time I want to insert this value to Database. Here is the problem. Differently they are working perfectly. But combined it is problem.
Here is the problem snipet.
Data:
todo: null,
todoList: []
Form to submit:
<form class="w-100" #submit="createTodo">
<div class="form-group w-100">
<input type="text" class="form-control w-100" placeholder="What needs to be done? " v-model="todo">
</div>
</form>
Todo Print:
<ul>
<li v-for="todo in todoList">
{{ todo.todo_title }}
</li>
</ul>
Method of inserting data into db:
createTodo(e) {
// Pushing dot only
app.todoList.push(this.todo)
let formData = new FormData();
formData.append('todo_title', this.todo)
axios({
method: 'POST',
url: 'api/todos.php',
data: formData
}).then(function(res){
}).catch(function(res){
console.log(res)
});
this.todo = null
e.preventDefault();
}
What can I do to do it perfectly.
For starters I would say that a more standard way of doing it is pushing the todo in the Axios promise callback. This way you could also include the ID that is created from the backend in the object.
It's not entirely clear what the issue is, if the issue is that you get the li but empty name, the problem is that when you're doing app.todoList.push(this.todo) you're printing the 'todo_title'. What you need to do is push it with the key app.todoList.push({ todo_title: this.todo }).

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.

Ember.js 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
});
}
}
});

File Upload using AJAX in Struts2 without page refresh

I want to upload file using Struts2, but without refreshing page.
How can I use AJAX for this solution.
$.ajax({
url:"strutsaction",
type : 'POST',
async: false,
});
What should I write for data and contentType in ajax request ?
jsp code:
<s:form action="strutsaction" method="post" enctype="multipart/form-data">
<s:file name="imgFileUpload" label="Choose file to upload" accept="image/*"></s:file>
<s:submit value="Upload" align="center"></s:submit>
</s:form>
Hi the below code is working for me. I hope it will help you.
JSP Code:
<div id="uploadImg">
<s:form id="uploadImgForm" action="strutsaction" method="post" enctype="multipart/form-data">
<s:file name="imgFileUpload" label="Choose file to upload" accept="image/*"></s:file>
<s:submit value="Upload" align="center" id="uploadImgSubmitBtn"></s:submit>
</s:form>
<div>
JQuery:
$("#uploadImgSubmitBtn").click(function(e){
// Get form
var form = $('#uploadImgForm')[0];
// Create an FormData object
var data = new FormData(form);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "strutsaction.action",
data : data,
cache: false,
processData: false,
contentType: false,
success: function(data){
$('#uploadImg').html(data);
}
});
});