How can I do a multipart Post in Dart / AngularDart - dart

I've got a REST api which assumes a multipartfile in the a post method.
Is there any way to do this kind of posts in Dart / AngularDart because all the solutions I've found so far are not working.
I've tried to use the http://dart-gde.github.io/dart-google-oauth2-library/multipart_file/MultipartFile.html solution, but it is not working in the browser because dart.io is not supported there.
My question is about the client side part directly from the browser. The serverside, which is written in Java can handle the post.

If you need multipart for file upload, all you have to do is send a FormData object using the HttpRequest class. Example:
import "dart:html";
...
var fileData; //file data to be uploaded
var formData = new FormData();
formData.append("field", "value"); //normal form field
formData.appendBlob("data", fileData); //binary data
HttpRequest.request("/service-url", method: "POST", sendData: formData).then((req) {
...
});
Furthermore, if you need to allow the user to upload a file from his hard disk, you have to use a html form with an <input type="file"> tag. Example:
Html file:
<form id="myForm" action="/service-url" method="POST" enctype="multipart/form-data">
<input type="text" name="field"> <!-- normal field -->
<input type="file" name="fileData"> <!-- file field -->
</form>
dart file:
var formData = new FormData(querySelector("#myForm"));
HttpRequest.request("/service-url", method: "POST", sendData: formData).then((req) {
...
});

I know this was asked a long time ago, but I've just had the same problem and the fix for me is the following (based on luizmineo's answer):
Use formData.appendBlob("data", fileData);
Don't set an explicit Content-Type header. This will get Dart to calculate the boundary section of the form-data which is crucial.

I finally found a way to post it as a multi-part form:
void uploadFiles() {
var formData = new FormData(querySelector("#fileForm"));
HttpRequest.request("/sp/file", method: "POST", sendData: formData).then((req) {
print("OK");
});
}
is used in conjunction with
<form id="fileForm" action="/sp/file" method="POST">
<input type="file" #upload (change)="uploadFiles(upload.files)"
(dragenter)="upload.style.setProperty('border', '3px solid green')"
(drop)="upload.style.setProperty('border', '2px dotted gray')" class="uploadDropZone" name="toUpload"/>

Related

Is there a way to get a QR code image with Google Apps Script using the POST method of the Google Charts API?

I am using a Google Script to generate tickets to an event, and the ticket includes a QR code which goes to a pre-filled Google Form link. Since it's pre-filled, the string is quite long, and the Google Charts API for creating QR codes will not accept a string of text that long using a GET request, but I can't find any documentation of how to code the POST request into Apps Script. How do I generate a POST request in Apps Script that will return an image of the QR code which I can then insert into the document?
I already tried the GET request, and it truncates the URL before encoding it into a QR code. That gets me to the Google Form, but not the pre-filled version that the link generates (actually pretty smart on Google's part to have it truncate the string in a place that still gives a usable URL, but that's for another day...)
I have also tried the HtmlService to render the QR code using the POST method with the Charts API in an HTML form that automatically submits on the loading of that HTML. If I use showSidebar(), this will open the image in a new tab, but I haven't figured out how to return that image so that it can be inserted into the document.
I've also tried creating a blob with the HTML and then saving the blob as a PNG, but from the research I've done, the .getAs() method doesn't render images when converting the HTML.
The renderQR function:
function renderQR(inputUrl) {
var html = HtmlService.createTemplateFromFile('QREncode.html');
html.url = inputUrl;
var rendered = html.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setHeight(300)
.setWidth(300);
return rendered;
}
The QREncode.html file:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script type='application/javascript'>
// Send the POST when the page is loaded,
// which will replace this whole page with the retrieved chart.
function loadGraph() {
var frm = document.getElementById('post_form');
if (frm) {
frm.submit();
}
}
</script>
</head>
<body onload="loadGraph()">
<form action='https://chart.googleapis.com/chart' method='POST' id='post_form'>
<input type='hidden' name='cht' value='qr' />
<input type='hidden' name='chl' value='<?= url ?>' />
<input type='hidden' name='chs' value='300x300' />
<input type='submit'/>
</form>
</body>
</html>
When I treat the return from the renderQR() function as an image, Apps script gives an error saying that it is "Invalid image data", which makes sense -- but how do I convert it into an image, or is there a better or simpler way I could be doing this?
You need to get the qr code in the Apps Script, not in the browser:
var imageData = UrlFetchApp.fetch('https://chart.googleapis.com/chart', {
'method' : 'post',
'payload' : {
'cht': 'qr',
'chl': 'https://google.com',
'chs': '300x300'
}}).getContent();
For those looking for a formula solution (without Apps Script)
Reference: https://www.benlcollins.com/spreadsheets/qr-codes-in-google-sheets/
Solution:
=IMAGE("https://chart.googleapis.com/chart?chs=250x250&cht=qr&chl="&ENCODEURL(A1))

uploading images using Angular 4 and carrierwave

I am trying to make an app that uses an angular 4 front end with a rails back end. I am currently trying to figure out how to upload images to my rails back end server using carrierwave. I am very stuck, there is very little information out there on how to implement Angular 4 with rails and carrierwave. I cannot figure out how to get it to upload the image to the rails server, when I inspect the rails console I get the below message. from what I can tell there is nothing being posted for some reason and I do not know why this is. If anyone who knows more about angular and rails could help that would be great.
rails console message when I try to upload image:
Processing by ImagesController#create as HTML
Parameters: {"images"=>{}}
Completed 400 Bad Request in 1ms (ActiveRecord: 6.0ms)
HTML
<input type="file" #selectFile id="selectFile" name="selectFile" class="btn btn-success">
<input type="button" class="btn btn-primary" (click)="uploadImage()" value="Upload Image">
upload-image.component.ts
export class UploadImageComponent{
#ViewChild('selectFile') selectFile;
constructor(private uploadService: UploadService) {}
uploadImage(){
let files = this.selectFile.nativeElement.files[0];
this.uploadService.uploadImage(files).subscribe(data => {return true},
error => {
console.log("error uploading image");
return Observable.throw(error);
})
}
upload-service.ts
#Injectable()
export class StallionService {
headers: Headers;
options: RequestOptions;
private imagesUrl = 'http://localhost:3000/images';
constructor(private http: Http) {
this.headers = new Headers({'Content-Type':'application/json'});
this.options = new RequestOptions({headers: this.headers});
}
uploadImage(image: File){
console.log(image);
const formData = new FormData();
formData.append("img", image);
console.log(formData);
return this.http.post(this.imagesUrl, formData,
this.options).map((res: Response) => res.json());
}
}
I can't see any errors in your code and i am a bit surprised that no params are shown in your rails console.
But i can show you how i did.
A simple solution (in Angular 2):
With the way you've set it up, i've found that it's very complex to save an image like that with Carrierwave and Angular.
A simpler solution is to use Base64 and the gem Carrierwave Base64 and Angulars FormGroup and FormController.
You could then use FileReader on change to set your file-input to the value:
<!-- part of a FormGroup called imageForm -->
<input formControlName="file" (change)="setImageFile($event)" type="file" id="selectFile" name="selectFile" class="btn btn-success">
And then in your component:
setImageFile(event) {
this.image_file = event.target.files[0];
if(this.image_file) {
const file_reader = new FileReader();
file_reader.readAsDataURL(this.image_file);
file_reader.onload = (e: any) => {
this.imageForm.get('file').setValue(file_reader.result);
}
}
}
And then on your upload you can send imageForm.value in your post request.
With the base64 gem you have to change one line (read on the GitHub page) but otherwise things will work as before and you are now able to save the image to the AWS etc..
I hope you get the idea - it worked for me! :)

How do I save an Angular form to my ruby on rails backend?

I'm new to Angular. I've tried everything I know how and Google searches have surprisingly few tutorials on this particular question. Here's the last code I tried:
index.html
<form ng-submit="addArticle(articles)">
<input type="text" id="title" ng-model="newPost.title">
<input type="text" id="body" ng-model="newPost.body">
<input type="submit" value="Submit">
</form>
articles controller
app.controller('ArticlesCtrl', function($scope, Article) {
$scope.articles = Article.query();
$scope.newPost = Article.save();
});
articles service (rails backend)
app.factory('Article', function($resource) {
return $resource('http://localhost:3000/articles');
});
I can retrieve data just fine. But I can't submit any new data to the rails backend. On page load, the rails server error is:
Started POST "/articles" for 127.0.0.1 at 2015-02-08 18:26:29 -0800
Processing by ArticlesController#create as HTML
Completed 400 Bad Request in 0ms
ActionController::ParameterMissing (param is missing or the value is empty: article):
app/controllers/articles_controller.rb:57:in `article_params'
app/controllers/articles_controller.rb:21:in `create'
Pressing the submit button does nothing at all. The form basically does not work and the page is looking for a submission as soon as it loads.
I understand what the error says, that it's not receiving the parameters from the form. What I don't understand is what that should look like in my controller and/or form.
What am I doing wrong and how do I fix this?
Angular has a feature called services which acts as a model for the application. It's where I'm communicating with my Rails backend:
services/article.js
app.factory('Article', function($resource) {
return $resource('http://localhost:3000/articles/:id', { id: '#id'},
{
'update': { method: 'PUT'}
});
});
Even though the :id is specified on the end, it works just as well for going straight to the /articles path. The id will only be used where provided.
The rest of the work goes into the controller:
controllers/articles.js
app.controller('NewPostCtrl', function($scope, Article) {
$scope.newPost = new Article();
$scope.save = function() {
Article.save({ article: $scope.article }, function() {
// Optional function. Clear html form, redirect or whatever.
});
};
});
Originally, I assumed that the save() function that's made available through $resources was somewhat automatic. It is, but I was using it wrong. The default save() function can take up to four parameters, but only appears to require the data being passed to the database. Here, it knows to send a POST request to my backend.
views/articles/index.html
<form name="form" ng-submit="save()">
<input type="text" id="title" ng-model="article.title">
<input type="text" id="body" ng-model="article.body">
<input type="submit" value="Submit">
</form>
After getting the service setup properly, the rest was easy. In the controller, it's required to create a new instance of the resource (in this case, a new article). I created a new $scope variable that contains the function which invokes the save method I created in the service.
Keep in mind that the methods created in the service can be named whatever you want. The importance of them is the type of HTTP request being sent. This is especially true for any RESTful app, as the route for GET requests is the same as for POST requests.
Below is the first solution I found. Thanks again for the responses. They were helpful in my experiments to learn how this worked!
Original Solution:
I finally fixed it, so I'll post my particular solution. However, I only went this route through lack of information how to execute this through an angular service. Ideally, a service would handle this kind of http request. Also note that when using $resource in services, it comes with a few functions one of which is save(). However, this also didn't work out for me.
Info on $http: https://docs.angularjs.org/api/ng/service/$http
Info on $resource: https://docs.angularjs.org/api/ngResource/service/$resource
Tutorial on Services and Factories (highly useful): http://viralpatel.net/blogs/angularjs-service-factory-tutorial/
articles.js controller
app.controller('FormCtrl', function($scope, $http) {
$scope.addPost = function() {
$scope.article = {
'article': {
'title' : $scope.article.title,
'body' : $scope.article.body
}
};
// Why can't I use Article.save() method from $resource?
$http({
method: 'POST',
url: 'http://localhost:3000/articles',
data: $scope.article
});
};
});
Since Rails is the backend, sending a POST request to the /articles path invokes the #create method. This was a simpler solution for me to understand than what I was trying before.
To understand using services: the $resource gives you access to the save() function. However, I still haven't demystified how to use it in this scenario. I went with $http because it's function was clear.
Sean Hill has a recommendation which is the second time I've seen today. It may be helpful to anyone else wrestling with this issue. If I come across a solution which uses services, I'll update this.
Thank you all for your help.
I've worked a lot with Angular and Rails, and I highly recommend using AngularJS Rails Resource. It makes working with a Rails backend just that much easier.
https://github.com/FineLinePrototyping/angularjs-rails-resource
You will need to specify this module in your app's dependencies and then you'll need to change your factory to look like this:
app.factory('Article', function(railsResourceFactory) {
return railsResourceFactory({url: '/articles', name: 'article');
});
Basically, based on the error that you are getting, what is happening is that your resource is not creating the correct article parameter. AngularJS Rails Resource does that for you, and it also takes care of other Rails-specific behavior.
Additionally, $scope.newPost should not be Article.save(). You should initialize it with a new resource new Article() instead.
Until your input fields are blank, no value is stored in model and you POST empty article object. You can fix it by creating client side validation or set default empty string value on needed fields before save.
First of all you should create new Article object in scope variable then pass newPost by params or access directly $scope.newPost in addArticle fn:
app.controller('ArticlesCtrl', function($scope, Article) {
$scope.articles = Article.query();
$scope.newPost = new Article();
$scope.addArticle = function(newPost) {
if (newPost.title == null) {
newPost.title = '';
}
// or if you have underscore or lodash:
// lodash.defaults(newPost, { title: '' });
Article.save(newPost);
};
});
If you want use CRUD operations you should setup resources like below:
$resource('/articles/:id.json', { id: '#id' }, {
update: {
method: 'PUT'
}
});

How to replace an AJAX post with Coldfusion within a cfc

I have been trying to find a way to do something that seems to be pretty simple but can't seem to find a solution out there. I have a post that is made with some HTML in it and would like to dynamically change portions of it. I am using Coldfusion 9 for server side, AJAX, and jQuery UI 1.10.1 & jQuery 1.9.1.
What I would like to do is post in AJAX and replace the data server side within the cfc. Here is the code I have on the Client side.
var ipost = '<li> <h2>Persons Name</h2> </li>';
var message_a = $('#message_a').attr('value');
$.ajax({
type: "POST",
url: "cfc/cfc_Forum.cfc?method=func_AddNew&returnformat=json",
data: { message:"message_a=" + wall_post },
success: function () {
$('ul#posts').prepend(ipost);
}
});
I would like to replace the "PersonsID" with a "Session.Variable1" and "Persons Name" with "Session.Variable2". The cfc would be standard protocol for CF. Here is what the component would look like.
<cfcomponent>
<cffunction name="func_AddNew" access="remote" returntype="struct">
<cfargument name="message" type="string" required="true" />
<--- ********** replace "Persons ID" and "Persons Name" ************** --->
<!--- ********* INSERT INTO DATA BASE ************ --->
<cfreturn return />
</cffunction>
</cfcomponent>
Any recommendations would be great!
The code below will work but it does expose the person's personID if they were to look at the source code so there is a bit of a risk doing this. The other thing you could do is pass the cftolken and try to find the correct variables in the cfc which takes a bit more effort.
$.ajax({
type: "POST",
url: "cfc/cfc_Forum.cfc?method=func_AddNew&returnformat=json",
data: { message:"message_a=" + wall_post
, personID: <cfoutput>#Session.Variable1#</cfoutput>
, personName: <cfoutput>#Session.Variable2#</cfoutput>
},
success: function () {
$('ul#posts').prepend(ipost);
}
});

Special charactes in query parameter

I am using 1 search option on my form. Here when i pass any special
characters like & or $ it does not hold that request parameter in the search box yeah but it is processing my request of search.
You need to URL encode the values in the query string.
I don't know Java but I used code similar to that below when sending user text to Google translate via Google URL parameter. (Assume values for myText, myURL, and myTextURL are already assigned.)
<script>
function transfix(isURL,form) {
if(isURL) window.open( myURL + encodeURIComponent(myText) );
else window.open( myTextURL + decodeURIComponent(myText) );
}
</script>
<form target=_blank id="translate" name="translate">
<input type="button" value="Text" onclick="transfix(false,this.form)">
<input type="button" value="URL" onclick="transfix(true,this.form)">
</form>

Resources