Related
I'm trying to make an ajax call (I specifically don't want to do it using ActionLink).
I'm having a controller that is like this:
public IActionResult ExportUsers(List<string> listOfEmails)
{
/*some data processing*/
return File(result, "text/csv", "ExportCandidates.csv");
}
On the other side with ajax I do this simple call:
$.ajax({
url: '/Admin/Testcenter/GenerateInvitationPreview',
type: 'post',
data: {
//some input data to send to the controller
},
success: function (response) {
)
}
});
I know there exists something for pdf files where you return a base64 file and with the response in the ajax call you just write something like pdfWindow.document.write(...) and this will open a new window with a pdf file.
Is there a way to extract the response for my CSV file and generate it so the user downloads it ?
USE NPOI Library for Excel Sheet Generation
//Generate Excel Sheet
try
{
Guid gid = Guid.NewGuid();
string ext = ".xls";
string[] Headers = { "Appointments Id", "Date of Appointment", "Doctor Name", "Patient Name", "Visit Type", "Status" };
string fileName = "AppointmentsExcelSheet_" + gid.ToString() + ext;
var serverpath = _env.ContentRootPath;
string rootpath = serverpath + "/wwwroot/ExcelSheets/" + fileName;
FileInfo file = new FileInfo(Path.Combine(rootpath, fileName));
var memorystream = new MemoryStream();
using (var fs = new FileStream(rootpath, FileMode.Create, FileAccess.Write))
{
IWorkbook workbook = new XSSFWorkbook();
ISheet excelSheet = workbook.CreateSheet("Appointments List");
IRow row = excelSheet.CreateRow(0);
var font = workbook.CreateFont();
font.FontHeightInPoints = 11;
font.FontName = "Calibri";
font.Boldweight = (short)FontBoldWeight.Bold;
for (var i = 0; i < Headers.Length; i++)
{
var cell = row.CreateCell(i);
cell.SetCellValue(Headers[i]);
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(font);
}
var result = _Appointment.GetAppoinmentsPDf();
int index = 1;
foreach (var app in result.Items)
{
//var PatientDob = Convert.ToDouble(app.PatientDOB);
row = excelSheet.CreateRow(index);
row.CreateCell(0).SetCellValue(app.AppointmentId);
row.CreateCell(1).SetCellValue(app.DateofAppointment+" "+app.TimeofAppointment);
row.CreateCell(2).SetCellValue(app.DoctorFullName);
row.CreateCell(3).SetCellValue(app.SelectedPatientName);
row.CreateCell(4).SetCellValue(app.PurposeofVisit);
if (app.IsActive == false)
{
row.CreateCell(5).SetCellValue("Inactive");
}
else
{
row.CreateCell(5).SetCellValue("Active");
}
index++;
}
workbook.Write(fs);
}
using (var filestream = new FileStream(rootpath, FileMode.Open))
{
filestream.CopyToAsync(memorystream);
}
memorystream.Position = 0;
//send filepath to JQuery function
response.Msg = "/ExcelSheets/" + fileName;
}
catch (Exception Ex)
{
//exception code
}
return Ok(reponse.Msg)
//JavaScript
function AppointmentsExcelSheet() {
//var token = Token;
//var link = path;
debugger
$.ajax({
//'Content-Type': 'application/pdf.',
type: "GET",
url: "/api/Appointments/GetAppointmentsExcelSheet",
beforeSend: function () {
$.blockUI({
message: ('<img src="/images/FadingLines.gif"/>'),
css: {
backgroundColor: 'none',
border: '0',
'z-index': 'auto'
}
});
},
complete: function () {
$.unblockUI();
},
success: function (data) {
debugger
//downloads your Excel sheet
window.location.href = data.msg;
}
});
}
The best way to do what you want to do is to not use AJAX, but use either a link click that opens a new window (since you are passing in parameters) If you could use a
<form target="_blank">
to open a form response. Inside the form can be a field or fields that contains the list of emails (it can be one field, or multiple input fields with the same name). Your action handler can accept that list, parse it, and return a File response, and the natural result of opening the new window from the form post operation is a file that opens up.
I have a folder named "images" in the same directory as my .js file. I want to load all the images from "images" folder into my html page using Jquery/Javascript.
Since, names of images are not some successive integers, how am I supposed to load these images?
Works both localhost and on live server without issues, and allows you to extend the delimited list of allowed file-extensions:
var folder = "images/";
$.ajax({
url : folder,
success: function (data) {
$(data).find("a").attr("href", function (i, val) {
if( val.match(/\.(jpe?g|png|gif)$/) ) {
$("body").append( "<img src='"+ folder + val +"'>" );
}
});
}
});
NOTICE
Apache server has Option Indexes turned on by default - if you use another server like i.e. Express for Node you could use this NPM package for the above to work: https://github.com/expressjs/serve-index
If the files you want to get listed are in /images than inside your server.js you could add something like:
const express = require('express');
const app = express();
const path = require('path');
// Allow assets directory listings
const serveIndex = require('serve-index');
app.use('/images', serveIndex(path.join(__dirname, '/images')));
Use :
var dir = "Src/themes/base/images/";
var fileextension = ".png";
$.ajax({
//This will retrieve the contents of the folder if the folder is configured as 'browsable'
url: dir,
success: function (data) {
//List all .png file names in the page
$(data).find("a:contains(" + fileextension + ")").each(function () {
var filename = this.href.replace(window.location.host, "").replace("http://", "");
$("body").append("<img src='" + dir + filename + "'>");
});
}
});
If you have other extensions, you can make it an array and then go through that one by one using in_array().
P.s : The above source code is not tested.
This is the way to add more file extentions, in the example given by Roy M J in the top of this page.
var fileextension = [".png", ".jpg"];
$(data).find("a:contains(" + (fileextension[0]) + "), a:contains(" + (fileextension[1]) + ")").each(function () { // here comes the rest of the function made by Roy M J
In this example I have added more contains.
If interested in doing this without jQuery - here's a pure JS variant (from here) of the answer currently most upvoted:
var xhr = new XMLHttpRequest();
xhr.open("GET", "/img", true);
xhr.responseType = 'document';
xhr.onload = () => {
if (xhr.status === 200) {
var elements = xhr.response.getElementsByTagName("a");
for (x of elements) {
if ( x.href.match(/\.(jpe?g|png|gif)$/) ) {
let img = document.createElement("img");
img.src = x.href;
document.body.appendChild(img);
}
};
}
else {
alert('Request failed. Returned status of ' + xhr.status);
}
}
xhr.send()
Here is one way to do it. Involves doing a little PHP as well.
The PHP part:
$filenameArray = [];
$handle = opendir(dirname(realpath(__FILE__)).'/images/');
while($file = readdir($handle)){
if($file !== '.' && $file !== '..'){
array_push($filenameArray, "images/$file");
}
}
echo json_encode($filenameArray);
The jQuery part:
$.ajax({
url: "getImages.php",
dataType: "json",
success: function (data) {
$.each(data, function(i,filename) {
$('#imageDiv').prepend('<img src="'+ filename +'"><br>');
});
}
});
So basically you do a PHP file to return you the list of image filenames as JSON, grab that JSON using an ajax call, and prepend/append them to the html. You would probably want to filter the files u grab from the folder.
Had some help on the php part from 1
$(document).ready(function(){
var dir = "test/"; // folder location
var fileextension = ".jpg"; // image format
var i = "1";
$(function imageloop(){
$("<img />").attr('src', dir + i + fileextension ).appendTo(".testing");
if (i==13){
alert('loaded');
}
else{
i++;
imageloop();
};
});
});
For this script, I have named my image files in a folder as 1.jpg, 2.jpg, 3.jpg, ... to 13.jpg.
You can change directory and file names as you wish.
Based on the answer of Roko C. Buljan, I have created this method which gets images from a folder and its subfolders . This might need some error handling but works fine for a simple folder structure.
var findImages = function(){
var parentDir = "./Resource/materials/";
var fileCrowler = function(data){
var titlestr = $(data).filter('title').text();
// "Directory listing for /Resource/materials/xxx"
var thisDirectory = titlestr.slice(titlestr.indexOf('/'), titlestr.length)
//List all image file names in the page
$(data).find("a").attr("href", function (i, filename) {
if( filename.match(/\.(jpe?g|png|gif)$/) ) {
var fileNameWOExtension = filename.slice(0, filename.lastIndexOf('.'))
var img_html = "<img src='{0}' id='{1}' alt='{2}' width='75' height='75' hspace='2' vspace='2' onclick='onImageSelection(this);'>".format(thisDirectory + filename, fileNameWOExtension, fileNameWOExtension);
$("#image_pane").append(img_html);
}
else{
$.ajax({
url: thisDirectory + filename,
success: fileCrowler
});
}
});}
$.ajax({
url: parentDir,
success: fileCrowler
});
}
This is the code that works for me, what I want is to list the images directly on my page so that you just have to put the directory where you can find the images for example -> dir = "images /"
I do a substring var pathName = filename.substring (filename.lastIndexOf ('/') + 1);
with which I make sure to just bring the name of the files listed and at the end I link my URL to publish it in the body
$ ("body"). append ($ ("<img src =" + dir + pathName + "> </ img>"));
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<script src="jquery-1.6.3.min.js"></script>
<script>
var dir = "imagenes/";
var fileextension = ".jpg";
$.ajax({
//This will retrieve the contents of the folder if the folder is configured as 'browsable'
url: dir,
success: function (data) {
//Lsit all png file names in the page
$(data).find("a:contains(" + fileextension + ")").each(function () {
var filename = this.href.replace(window.location.pathname, "").replace("http://", "");
var pathName = filename.substring(filename.lastIndexOf('/') + 1);
$("body").append($("<img src=" + dir + pathName + "></img>"));
console.log(dir+pathName);
});
}
});
</script>
</head>
<body>
<img src="1_1.jpg">
</body>
</html>
If, as in my case, you would like to load the images from a local folder on your own machine, then there is a simple way to do it with a very short Windows batch file. This uses the ability to send the output of any command to a file using > (to overwrite a file) and >> (to append to a file).
Potentially, you could output a list of filenames to a plain text file like this:
dir /B > filenames.txt
However, reading in a text file requires more faffing around, so I output a javascript file instead, which can then be loaded in your to create a global variable with all the filenames in it.
echo var g_FOLDER_CONTENTS = mlString(function() { /*! > folder_contents.js
dir /B images >> folder_contents.js
echo */}); >> folder_contents.js
The reason for the weird function with comment inside notation is to get around the limitation on multi-line strings in Javascript. The output of the dir command cannot be formatted to write a correct string, so I found a workaround here.
function mlString(f) {
return f.toString().
replace(/^[^\/]+\/\*!?/, '').
replace(/\*\/[^\/]+$/, '');
}
Add this in your main code before the generated javascript file is run, and then you will have a global variable called g_FOLDER_CONTENTS, which is a string containing the output from the dir command. This can then be tokenized and you'll have a list of filenames, with which you can do what you like.
var filenames = g_FOLDER_CONTENTS.match(/\S+/g);
Here's an example of it all put together: image_loader.zip
In the example, run.bat generates the Javascript file and opens index.html, so you needn't open index.html yourself.
NOTE: .bat is an executable type in Windows, so open them in a text editor before running if you are downloading from some random internet link like this one.
If you are running Linux or OSX, you can probably do something similar to the batch file and produce a correctly formatted javascript string without any of the mlString faff.
You can't do this automatically. Your JS can't see the files in the same directory as it.
Easiest is probably to give a list of those image names to your JavaScript.
Otherwise, you might be able to fetch a directory listing from the web server using JS and parse it to get the list of images.
In jQuery you can use Ajax to call a server-side script. The server-side script will find all the files in the folder and return them to your html file where you will need to process the returned information.
You can use the fs.readdir or fs.readdirSync methods to get the file names in the directory.
The difference between the two methods, is that the first one is asynchronous, so you have to provide a callback function that will be executed when the read process ends.
The second is synchronous, it will returns the file name array, but it will stop any further execution of your code until the read process ends.
After that you simply have to iterate through the names and using append function, add them to their appropriate locations. To check out how it works see HTML DOM and JS reference
Add the following script:
<script type="text/javascript">
function mlString(f) {
return f.toString().
replace(/^[^\/]+\/\*!?/, '');
replace(/\*\/[^\/]+$/, '');
}
function run_onload() {
console.log("Sample text for console");
var filenames = g_FOLDER_CONTENTS.match(/\S+/g);
var fragment = document.createDocumentFragment();
for (var i = 0; i < filenames.length; ++i) {
var extension = filenames[i].substring(filenames[i].length-3);
if (extension == "png" || extension == "jpg") {
var iDiv = document.createElement('div');
iDiv.id = 'images';
iDiv.className = 'item';
document.getElementById("image_div").appendChild(iDiv);
iDiv.appendChild(fragment);
var image = document.createElement("img");
image.className = "fancybox";
image.src = "images/" + filenames[i];
fragment.appendChild(image);
}
}
document.getElementById("images").appendChild(fragment);
}
</script>
then create a js file with the following:
var g_FOLDER_CONTENTS = mlString(function() { /*!
1.png
2.png
3.png
*/});
Using Chrome, searching for the images files in links (as proposed previously) didn't work as it is generating something like:
(...) i18nTemplate.process(document, loadTimeData);
</script>
<script>start("current directory...")</script>
<script>addRow("..","..",1,"170 B","10/2/15, 8:32:45 PM");</script>
<script>addRow("fotos-interessantes-11.jpg","fotos-interessantes-> 11.jpg",false,"","");</script>
Maybe the most reliable way is to do something like this:
var folder = "img/";
$.ajax({
url : folder,
success: function (data) {
var patt1 = /"([^"]*\.(jpe?g|png|gif))"/gi; // extract "*.jpeg" or "*.jpg" or "*.png" or "*.gif"
var result = data.match(patt1);
result = result.map(function(el) { return el.replace(/"/g, ""); }); // remove double quotes (") surrounding filename+extension // TODO: do this at regex!
var uniqueNames = []; // this array will help to remove duplicate images
$.each(result, function(i, el){
var el_url_encoded = encodeURIComponent(el); // avoid images with same name but converted to URL encoded
console.log("under analysis: " + el);
if($.inArray(el, uniqueNames) === -1 && $.inArray(el_url_encoded, uniqueNames) === -1){
console.log("adding " + el_url_encoded);
uniqueNames.push(el_url_encoded);
$("#slider").append( "<img src='" + el_url_encoded +"' alt=''>" ); // finaly add to HTML
} else{ console.log(el_url_encoded + " already in!"); }
});
},
error: function(xhr, textStatus, err) {
alert('Error: here we go...');
alert(textStatus);
alert(err);
alert("readyState: "+xhr.readyState+"\n xhrStatus: "+xhr.status);
alert("responseText: "+xhr.responseText);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am trying to download different sections of a page as jpeg. There are two ways I'm going about it; One is to include a download button in every section and when it is clicked, the section is downloaded as jpeg; The other is to include a button atop the page and when it is clicked, all the sections are downloaded.
The download section by section code works well but the issue arises when I try to do the download all option, It downloads files of type file instead of jpeg pictures.
When I logged the url I'm supposed to download from, I find out that it is empty but it isn't inside the html2canvas function.
I am using html2canvas to convert html to canvas and JSZip to zip it.
function urlToPromise(url) {
return new Promise(function(resolve, reject) {
JSZipUtils.getBinaryContent(url, function (err, data) {
if(err) {
reject(err);
} else {
resolve(data);
console.log(data);
}
});
});
}
function getScreen(){
var caption = $('#caption-input').val();
var allSections = $("#content").children().unbind();
var allSectionsArray = $.makeArray(allSections);
console.log(allSectionsArray);
var zip = new JSZip(); //Instantiate zip file
var url = "";
for(var i = 0; i < allSectionsArray.length; i++){
console.log("Currently at " + allSectionsArray[i].id);
var queryId = allSectionsArray[i].id.toString();
html2canvas(document.querySelector("#"+queryId)).then(function(canvas) {
$("#blank").attr('href',canvas.toDataURL('image/jpeg', 1.0));
$("#blank").attr('download',caption + ".jpeg");
//$("#blank")[0].click();
url = $("#blank").attr('href');
console.log(url);
});
console.log(url);
var filename = "image " + (i+1);
zip.file(filename, urlToPromise(url),{binary:true}); //Create new zip file with filename and content
console.log('file ' + (i+1) + ' generated');
console.log(filename+ "\n" + url);
}
//Generate zip file
generateZipFile(zip);
}
function generateZipFile(zip){
zip.generateAsync({type:"blob"})
.then(function callback(blob) {
saveAs(blob, "example.zip");
console.log("zip generated");
});
}
I need to print all the txt files from a directory inside an HTML using javascript.
i tried to modify a code dealing with photos but I didn't success
How to load all the images from one of my folder into my web page, using Jquery/Javascript
var dir = "D:\Finaltests\test1\new\places";
var fileextension = ".txt";
$.ajax({
//This will retrieve the contents of the folder if the folder is configured as 'browsable'
url: dir,
success: function (data) {
//List all .txt file names in the page
$(data).find("a:contains(" + fileextension + ")").each(function () {
var filename = this.href.replace(window.location.host, "").replace("http://", "");
$("body").append("<input type='file' onload='readText(" + dir + ")>");
});
}
});
You can use <input type="file"> with multiple attribute set, accept attribute set to text/plain; change event ;FileReader, for loop.
var pre = document.querySelector("pre");
document.querySelector("input[type=file]")
.addEventListener("change", function(event) {
var files = event.target.files;
for (var i = 0; i < files.length; i++) {
(function(file) {
var reader = new FileReader();
reader.addEventListener("load", function(e) {
pre.textContent += "\n" + e.target.result;
});
reader.readAsText(file)
}(files[i]))
}
})
<input type="file" accept="text/plain" multiple />
<pre>
</pre>
You can also use webkitdirectory and allowdirs attributes for directory upload at chrome, chromium; at nightly 45+ or firefox 42+ where dom.input.dirpicker preference set to true, see Firefox 42 for developers , Select & Drop Files and/or Folders to be parsed. Note, you can also drop folders from file manager at <input type="file"> element
var pre = document.querySelector("pre");
document.querySelector("input[type=file]")
.addEventListener("change", function(event) {
console.log(event.target.files)
var uploadFile = function(file, path) {
// handle file uploading
console.log(file, path);
var reader = new FileReader();
reader.addEventListener("load", function(e) {
pre.textContent += "\n" + e.target.result;
});
reader.readAsText(file)
};
var iterateFilesAndDirs = function(filesAndDirs, path) {
for (var i = 0; i < filesAndDirs.length; i++) {
if (typeof filesAndDirs[i].getFilesAndDirectories === 'function') {
var path = filesAndDirs[i].path;
// this recursion enables deep traversal of directories
filesAndDirs[i].getFilesAndDirectories()
.then(function(subFilesAndDirs) {
// iterate through files and directories in sub-directory
iterateFilesAndDirs(subFilesAndDirs, path);
});
} else {
uploadFile(filesAndDirs[i], path);
}
}
};
if ("getFilesAndDirectories" in event.target) {
event.target.getFilesAndDirectories()
.then(function(filesAndDirs) {
iterateFilesAndDirs(filesAndDirs, '/');
})
} else {
// do webkit stuff
var files = event.target.files;
for (var i = 0; i < files.length; i++) {
(function(file) {
uploadFile(file)
}(files[i]))
}
}
})
<!DOCTYPE html>
<html>
<head>
<script></script>
</head>
<body>
<input type="file" webkitdirectory allowdirs directory />
<pre>
</pre>
</body>
</html>
plnkr http://plnkr.co/edit/Y1XYd9rLOdKRHw6tb1Sh?p=preview
For ajax requests at chromium, chrome file: protocol local filesystem you can launch with --allow-file-access-from-files flag set, see Jquery load() only working in firefox?.
At firefox you can set security.fileuri.strict_origin_policy to false, see Security.fileuri.strict origin policy.
For a possible $.ajax() approach at chrome, chromium you can try
var path = "/path/to/drectory"; // `D:\`, `file:///`
var files = [];
$.ajax({url:path, dataType:"text html"})
.then((data) => {
// match file names from `html` returned by chrome, chromium
// for directory listing of `D:\Finaltests\test1\new\places`;
// you can alternatively load the "Index of" document and retrieve
// `.textContent` from `<a>` elements within `td` at `table` of
// rendered `html`; note, `RegExp` to match file names
// could probably be improved, does not match space characters in file names
var urls = $.unique(data.match(/\b(\w+|\d+)\.txt\b/g));
return $.when.apply($, $.map(urls, (file) => {
files.push(file);
// `\`, or `/`, depending on filesystem type
return $.ajax({url:path + "/" + file
, dataType:"text html"})
.then((data) => {
// return array of objects having property set to `file` name,
// value set to text within `file`
return {[file]:data}
})
}))
})
.then((...res) => {
console.log(res, files)
})
you can't reach the host filesystem with javascript for security reason.
The best you can do is to make a single ajax call to a server-side script (php for exemple) that will collect all html file and return them to your ajax call.
gethtml.php:
<?php
$output = "";
// your list of folders
$folders = [
'D:\Finaltests\test1\new\places1',
'D:\Finaltests\test1\old\places2',
'D:\Finaltests\test1\whatever\places3'
];
foreach ($folders as $key => $dir) {
if(!is_dir($dir))
continue;
// get all files of the directory
$files = scandir($dir);
foreach ($files as $file) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if(finfo_file($finfo, $file) == 'text/plain')
$output .= file_get_contents($dir . DIRECTORY_SEPARATOR . $file);
}
}
echo $output;
exit;
?>
Ajax call:
$.get('path/to/gethtml.php', function(response){
$('body').html(response);
});
you can change the line of php that check the mime type according to the type of the file you want to get (plain text or text/html or whatever)
Is it possible to upload a file using the Facebook Graph API using javascript, I feel like I'm close. I'm using the following JavaScript
var params = {};
params['message'] = 'PicRolled';
params['source'] = '#'+path;
params['access_token'] = access_token;
params['upload file'] = true;
function saveImage() {
FB.api('/me/photos', 'post', params, function(response) {
if (!response || response.error) {
alert(response);
} else {
alert('Published to stream - you might want to delete it now!');
}
});
}
Upon running this I receive the following error...
"OAuthException" - "(#324) Requires upload file"
When I try and research this method all I can find out about is a php method that apears to solve this
$facebook->setFileUploadSupport(true);
However, I am using JavaScript, it looks like this method might be to do with Facebook Graph permissions, but I already have set the permissions user_photos and publish_stream, which I believed are the only ones I should need to perform this operation.
I have seen a couple of unanswered questions regarding this on stackoverflow, hopefully I can explained myself enough. Thanks guys.
Yes, this is possible, i find 2 solutions how to do that and they are very similar
to each other, u need just define url parameter to external image url
FIRST one using Javascript SDk:
var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
FB.api('/album_id/photos', 'post', {
message:'photo description',
url:imgURL
}, function(response){
if (!response || response.error) {
alert('Error occured');
} else {
alert('Post ID: ' + response.id);
}
});
and SECOND one using jQuery Post request and FormData:
var postMSG="Your message";
var url='https://graph.facebook.com/albumID/photos?access_token='+accessToken+"&message="+postMSG;
var imgURL="http://farm4.staticflickr.com/3332/3451193407_b7f047f4b4_o.jpg";//change with your external photo url
var formData = new FormData();
formData.append("url",imgURL);
$.ajax({
url: url,
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'POST',
success: function(data){
alert("POST SUCCESSFUL");
}
});
EDIT: this answer is (now) largely irrelevant. If your image is on the web, just specify the url param as per the API (and see examples in other answers). If you would like to POST the image content to facebook directly, you may want to read this answer to gain understanding. Also see HTML5's Canvas.toDataUrl().
The API says: "To publish a photo, issue a POST request with the photo file attachment as multipart/form-data."
FB is expecting that the bytes of the image to be uploaded are in the body of the HTTP request, but they're not there. Or to look at it another way - where in the FB.api() call are you supplying the actual contents of the image itself?
The FB.api() API is poorly documented, and doesn't supply an example of an HTTP POST which includes a body. One might infer from the absence of such an example that it doesn't support this.
That's probably OK - FB.api() is using something called XmlHttpRequest under the covers which does support including a body ... look it up in your favourite JavaScript reference.
However, you'll still have 2 sub-problems to solve:
how to prepare the image bytes (and rest of the request) as multipart/form-data; and
getting the bytes of the image itself
(incidentally, the need to encode the message body is probably what the PHP setFileUploadSupport(true) method is for - tell the facebook object to encode the message body as multipart/form-data before sending)
But it's a bit meessier than that
Unfortunately, sub-problem '2' may bite you - there is no way (last time I looked) to extract the bytes of an image from the browser-supplied Image object.
If the image to be uploaded is accessible via a URL, you could fetch the bytes with XmlHttpRequest. Not too bad.
If the image is coming from the user's desktop, your probable recourse is to offer the user a:
<form enctype="multipart/form-data">
<input type="filename" name="myfile.jpg" />
<input type="hidden" name="source" value="#myfile.jpg"/>
<input type="hidden" name="message" value="My Message"/>
<input type="hidden" name="access_token" value="..."/>
</form>
(notice that source references the name given to the file-upload widget)
... and hope that FB anticipated receiving the data in this manner (try it with a static HTML form first, before coding it up dynamically in JS). One might infer that in fact it would, since they don't offer another means of doing it.
i used #Владимир Дворник code with some modification, I had the same issue and with this code it worked very well:
var imgURL = //your external photo url
FB.api('/photos', 'post', {
message: 'photo description',
access_token: your accesstoken
url: imgURL
}, function (response) {
if (!response || response.error) {
alert('Error occured:' + response);
} else {
alert('Post ID: ' + response.id);
}
});
Photos can be uploaded to facebook profile using Ajax as follows.
$.ajax({
type: "POST",
url: "https://graph.facebook.com/me/photos",
data: {
message: "Your Msg Goes Here",
url: "http://www.knoje.com/images/photo.jpg[Replace with yours]",
access_token: token,
format: "json"
},
success: function(data){
alert("POST SUCCESSFUL"); }
});
So this is the best way to post photo to a facebook profile with GRAPH API and is the simple one.
In many answer i have seen that image url is shwon by the source,picture or image etc but that doesn't works.
The use of of source,picture or image leads to a (#324) Requires upload file error .
Best way to avoid the 324 error.
Only #Thiago's answer is answering the question of uploading data via javascript. I've found that the Facebook JS API doesn't cover this situation.
I've also brew & tested my personl solution.
Main steps
Get the binary data of the image (I've used a canvas, but using an input box is possible as well)
Form a multipart request with all necesarry data for the graph API call
Include the binary data in the request
Encode everything in a binary array and send it so via XHR
Code
Conversion utilities
var conversions = {
stringToBinaryArray: function(string) {
return Array.prototype.map.call(string, function(c) {
return c.charCodeAt(0) & 0xff;
});
},
base64ToString: function(b64String) {
return atob(b64String);
}
};
Image posting snippet
var DEFAULT_CALL_OPTS = {
url: 'https://graph.facebook.com/me/photos',
type: 'POST',
cache: false,
success: function(response) {
console.log(response);
},
error: function() {
console.error(arguments);
},
// we compose the data manually, thus
processData: false,
/**
* Override the default send method to send the data in binary form
*/
xhr: function() {
var xhr = $.ajaxSettings.xhr();
xhr.send = function(string) {
var bytes = conversions.stringToBinaryArray(string);
XMLHttpRequest.prototype.send.call(this, new Uint8Array(bytes).buffer);
};
return xhr;
}
};
/**
* It composes the multipart POST data, according to HTTP standards
*/
var composeMultipartData = function(fields, boundary) {
var data = '';
$.each(fields, function(key, value) {
data += '--' + boundary + '\r\n';
if (value.dataString) { // file upload
data += 'Content-Disposition: form-data; name=\'' + key + '\'; ' +
'filename=\'' + value.name + '\'\r\n';
data += 'Content-Type: ' + value.type + '\r\n\r\n';
data += value.dataString + '\r\n';
} else {
data += 'Content-Disposition: form-data; name=\'' + key + '\';' +
'\r\n\r\n';
data += value + '\r\n';
}
});
data += '--' + boundary + '--';
return data;
};
/**
* It sets the multipart form data & contentType
*/
var setupData = function(callObj, opts) {
// custom separator for the data
var boundary = 'Awesome field separator ' + Math.random();
// set the data
callObj.data = composeMultipartData(opts.fb, boundary);
// .. and content type
callObj.contentType = 'multipart/form-data; boundary=' + boundary;
};
// the "public" method to be used
var postImage = function(opts) {
// create the callObject by combining the defaults with the received ones
var callObj = $.extend({}, DEFAULT_CALL_OPTS, opts.call);
// append the access token to the url
callObj.url += '?access_token=' + opts.fb.accessToken;
// set the data to be sent in the post (callObj.data = *Magic*)
setupData(callObj, opts);
// POST the whole thing to the defined FB url
$.ajax(callObj);
};
Usage
postImage({
fb: { // data to be sent to FB
caption: caption,
/* place any other API params you wish to send. Ex: place / tags etc.*/
accessToken: 'ACCESS_TOKEN',
file: {
name: 'your-file-name.jpg',
type: 'image/jpeg', // or png
dataString: image // the string containing the binary data
}
},
call: { // options of the $.ajax call
url: 'https://graph.facebook.com/me/photos', // or replace *me* with albumid
success: successCallbackFunction,
error: errorCallbackFunction
}
});
Extra
Extracting the binary string representation of a canvas image
var getImageToBeSentToFacebook = function() {
// get the reference to the canvas
var canvas = $('.some-canvas')[0];
// extract its contents as a jpeg image
var data = canvas.toDataURL('image/jpeg');
// strip the base64 "header"
data = data.replace(/^data:image\/(png|jpe?g);base64,/, '');
// convert the base64 string to string containing the binary data
return conversions.base64ToString(data);
}
Information on how to load the binaryString from an input[type=file]
HTML5 File API read as text and binary
Notes:
There are of course alternative approaches as well
Using an HTML form in an iframe - you cannot get the response from the call
Using a FormData & File approach, but unfortunately in this case there are a lot of incompatilities which make the process harder to use, and you would end up duct-taping around the inconsistencies - thus my choice was manual data assembly since HTTP standards rarely change :)
The solution does not require any special HTML5 features.
The above example uses jQuery.ajax, jQuery.extend, jQuery.each
Yes, you can do this posting data to an iframe like here, or you can use jQuery File Upload .
The problem is you can't get response from iframe, using plugin you can use a page handle.
Example: upload a video using jQuery File Upload
<form id="fileupload" action="https://graph-video.facebook.com/me/photos" method="POST" enctype="multipart/form-data">
<input type="hidden" name="acess_token" value="user_acess_token">
<input type="text" name="title">
<input type="text" name="description">
<input type="file" name="file"> <!-- name must be file -->
</form>
<script type="text/javascript">
$('#fileupload').fileupload({
dataType: 'json',
forceIframeTransport: true, //force use iframe or will no work
autoUpload : true,
//facebook book response will be send as param
//you can use this page to save video (Graph Api) object on database
redirect : 'http://pathToYourServer?%s'
});
</script>
To upload a file from the local computer with just Javascript try HelloJS
<form onsubmit="upload();">
<input type="file" name="file"/>
<button type="submit">Submit</button>
</form>
<script>
function upload(){
hello.api("facebook:/me/photos", 'post', document.getElementById('form'), function(r){
alert(r&&!r.error?'Success':'Failed');
});
}
</script>
There's an upload demo at http://adodson.com/hello.js/demos/upload.html
https://stackoverflow.com/a/16439233/68210 contains a solution that works if you need to upload the photo data itself and don't have a url.
This still works. I am using it as below:
var formdata= new FormData();
if (postAs === 'page'){
postTo = pageId; //post to page using pageID
}
formdata.append("access_token", accessToken); //append page access token if to post as page, uAuth|paAuth
formdata.append("message", photoDescription);
formdata.append("url", 'http://images/image.png');
try {
$.ajax({
url: 'https://graph.facebook.com/'+ postTo +'/photos',
type: "POST",
data: formdata,
processData: false,
contentType: false,
cache: false,
error: function (shr, status, data) {
console.log("error " + data + " Status " + shr.status);
},
complete: function () {
console.log("Successfully uploaded photo to Facebook");
}
});
} catch (e) {
console.log(e);
}
I have to ask though if you people have any idea if this is advisable or has a big security risk compared to using PHP api for Facebook.
This works:
function x(authToken, filename, mimeType, imageData, message) {
// this is the multipart/form-data boundary we'll use
var boundary = '----ThisIsTheBoundary1234567890';
// let's encode our image file, which is contained in the var
var formData = '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="source"; filename="' + filename + '"\r\n';
formData += 'Content-Type: ' + mimeType + '\r\n\r\n';
for (var i = 0; i < imageData.length; ++i) {
formData += String.fromCharCode(imageData[i] & 0xff);
}
formData += '\r\n';
formData += '--' + boundary + '\r\n';
formData += 'Content-Disposition: form-data; name="message"\r\n\r\n';
formData += message + '\r\n';
formData += '--' + boundary + '--\r\n';
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://graph.facebook.com/me/photos?access_token=' + authToken, true);
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary);
// Solving problem with sendAsBinary for chrome
try {
if (typeof XMLHttpRequest.prototype.sendAsBinary == 'undefined') {
XMLHttpRequest.prototype.sendAsBinary = function(text) {
var data = new ArrayBuffer(text.length);
var ui8a = new Uint8Array(data, 0);
for (var i = 0; i < text.length; i++) ui8a[i] = (text.charCodeAt(i) & 0xff);
this.send(ui8a);
}
}
} catch (e) {}
xhr.sendAsBinary(formData);
};
I seem to have a similar problem, but solutions above didn't work.
I was using the solution suggested by Arrabi (just use the url property only) to post images without any problem. My images are around 2-3 MB each.
When I migrated my app to another server (changing the absolute url of my images in the post) the method kept giving me 324 errors for images above around 100k size.
I thought it was due to some Apache setting on my end, but when I changed apache for lighttpd the problem was still there.
The connections from Facebook actually show up in my (apache) log:
69.171.234.7 - - [08/Jun/2012:11:35:54 +0200] "GET /images/cards/1337701633_518192458.png HTTP/1.1" 200 2676608 "-" "facebookplatform/1.0 (+http://developers.facebook.com)"
69.171.228.246 - - [08/Jun/2012:11:42:59 +0200] "GET /images/test5.jpg HTTP/1.1" 200 457402 "-" "facebookplatform/1.0 (+http://developers.facebook.com)"
69.171.228.246 - - [08/Jun/2012:11:43:17 +0200] "GET /images/test4.jpg HTTP/1.1" 200 312069 "-" "facebookplatform/1.0 (+http://developers.facebook.com)"
69.171.228.249 - - [08/Jun/2012:11:43:49 +0200] "GET /images/test2.png HTTP/1.1" 200 99538 "-" "facebookplatform/1.0 (+http://developers.facebook.com)"
69.171.228.244 - - [08/Jun/2012:11:42:31 +0200] "GET /images/test6.png HTTP/1.1" 200 727722 "-" "facebookplatform/1.0 (+http://developers.facebook.com)"
Only test2.png succeeded.
I use the following to share a photo (some BitmapData from the Phaser framework). It seems to work...
// Turn data URI to a blob ready for upload.
dataURItoBlob(dataURI:string): Blob {
var byteString = atob(dataURI.split(',')[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: 'image/jpeg' });
}
// Share the given bitmapData as a photo on Facebook
sharePhoto(accessToken: string, photo: BitmapData, message: string): void {
// Create form data, set up access_token, source and message
var fd = new FormData();
fd.append("access_token", accessToken);
fd.append("source", this.dataURItoBlob(photo.canvas.toDataURL("image/jpeg")));
fd.append("message", message);
var request = new XMLHttpRequest();
var thisPtr = this;
request.onreadystatechange = function () {
if (request.readyState == XMLHttpRequest.DONE) {
var json = JSON.parse(request.responseText);
if (json.hasOwnProperty("error")) {
var error = json["error"];
if (error.hasOwnProperty("type")) {
var errorType = error["type"];
if (errorType === "OAuthException") {
console.log("Need to request more permissions!");
}
}
}
} else if (request.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
} else if (request.readyState == XMLHttpRequest.LOADING) {
} else if (request.readyState == XMLHttpRequest.OPENED) {
} else if (request.readyState == XMLHttpRequest.UNSENT) {
}
}
request.open("POST", "https://graph.facebook.com/me/photos", true);
request.send(fd);
}
In case anyone still looking for how to upload directly from canvas to Facebook photos, this works for me:
function postImageToFacebook(token, imageData, message, successCallback, errorCallback) {
var fd = new FormData();
fd.append("access_token", token);
fd.append("source", imageData);
fd.append("caption", message);
$.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false,
success: function (data) {
successCallback(data);
},
error: function (shr, status, data) {
errorCallback(data);
},
complete: function (data) {
console.log('Completed');
}
});
}
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: 'image/jpeg'});
}
To use it
// *IMPORTANT*
var FBLoginScope = 'publish_actions'; // or sth like 'user_photos,publish_actions' if you also use other scopes.
var caption = "Hello Facebook!";
var successCallback = ...;
var errorCallback = ...;
var data = $('#your_canvas_id')[0].toDataURL("image/jpeg");
try {
imageData = dataURItoBlob(data);
} catch (e) {
console.log(e);
}
FB.getLoginStatus(function (response) {
if (response.status === "connected") {
postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
} else if (response.status === "not_authorized") {
FB.login(function (response) {
postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
}, {scope: FBLoginScope});
} else {
FB.login(function (response) {
postImageToFacebook(response.authResponse.accessToken, imageData, caption, successCallback, errorCallback);
}, {scope: FBLoginScope});
}
});
Modified from: http://gorigins.com/posting-a-canvas-image-to-facebook-and-twitter/