Uploading images using aurelia to asp.net core backend - javascript

I have been searching for a solution for this but none of the guides are updated or suited for my intention. I need a user uploaded image to be loaded into javascript/aurelia which then sends it to the asp.net core backend using its http fetch client so the image is saved on disk(not in a database). I'm currently using the following code but I'm getting the following error and no images are being saved.
extract from html code being used to upload image
<input class="hiddenButton" id="images" type="file" accept=".jpeg" file.bind="image">
<button class="upload" onclick="document.getElementById('images').click()">
<i class="fa fa-pencil" style="color:green"></i>
</button>
extract of javascript code used to invoke saving
save() {
this.api.saveEmployee(this.employee).then(employee => this.employee = employee);
this.ea.publish(new EmployeeAdded(this.employee));
this.api.saveImage(this.image);
return this.employee;
}
Javascript/aurelia code
saveImage(image) {
var form = new FormData()
form.append('image', image)
this.http.fetch('/api/Images', {
method: 'POST',
//headers: { 'Content-Type': image.type },
body: form
})
.then(response => {
return response
})
.catch(error => {
console.log("Some Failure...");
throw error.content;
})
return true;
}
Asp.net core MVC code(backend)
[HttpPost]
public async Task<IActionResult> SaveImage(IFormFile file)
{
Console.WriteLine("Images controller");
var filePath = Path.Combine(Directory.GetCurrentDirectory(),"Image");
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return Ok();
}
error message

The HTML element <input type="file" /> does not have a property file, the correct property is files, so it sounds like the problem is with aurelia/javascript and binding.
Since the property files is a FileList (collection) you will need to access the first file in the collection. Even though you haven't used multiple I think files will still be a collection.
You could try this:
// html
<input class="hiddenButton" id="images" type="file" accept=".jpeg" files.bind="image">
// ^ files
// jss/aurelia
saveImage(image) {
var form = new FormData();
form.append('image', image[0]); // access the first image in collection image[0]
// the other code remains the same
//...
}
PS I haven't used aurelia so can't be 100% sure this is the issue but hopefully points you in the correct direction.
PPS: since files is a collection, technically image in your view model is a collection too, so you could consider renaming it to images to make it clearer (even if you're only using one image). It should still work using image[0] but images[0] would be clearer.

Related

Uploading image using the <img attribute

I'm trying to see if it is possible to upload an image from the <img src=""> to a database, without using the input function
<form class="form-horizontal" validate="true" action="upload1.php" method="POST" enctype="multipart/form-data">
<a href="javascript:void(0)" class="closebtn" onclick="closeForm()"</a>
<img id="output" src="name.png" data-name="photo" width="100%"/>
<input type="hidden" name="photo" id="output" value="">
<input type="submit" name="reg" value="Update Status" class="btn btn-solid">
</form>
I just want to know if there's a way it could work
I am not sure why you do not want to use an input field, since this makes the image upload easier and also provides you a File object which inherits from a Blob and provides you info about the image like filename, lastModified, etc (see more here).
Regardless, yes this is possible in javascript using FormData. However, you would have to either convert the image to base64 (which I do not recommend because this makes the size about 33% larger), or use a Blob object and upload that (which also involves a hacky workaround using fetch). Here is an example of what you could do.
// Convert img to Blob
const img = document.getElementById('output');
fetch(img.src)
.then(res => res.blob())
.then(blob => {
// Prepare image for upload
const fd = new FormData();
fd.append('uploadedImage', blob, 'tmp.png');
// Upload
fetch(<image-upload-endpoint>, {
method: 'POST',
body: fd
})
.then(res => {
if (res.ok) {
// Upload was successful
} else {
// Upload failed
}
});
});
Then you would be able to retrieve the file in PHP with $_FILES['uploadedImage']

How to get file path from File object observer in v-file-input Vuetify?

I am building feature upload image with Vuetify. I need preview image before upload to server
In v-input-file
<v-file-input
accept="image/*"
multiple
label="Add your files"
chips
filled
prepend-icon="mdi-camera"
#change="onAddFiles"
></v-file-input>
In method change
onAddFiles(files) {
console.log(files);
}
You can see there is no information file path in File object observer array
I don't know how to get file path from this File object observer. Please help me and i'm so grateful!
in data, include the following
previews: [],
errorImage: "url of an image to use to indicate an error",
obviously you need to set errorImage to something useful
Then add some code to onAddFiles to generate an array of previews
onAddFiles(files) {
this.previews = [];
files.forEach((file, index) => {
const reader = new FileReader();
reader.addEventListener('load', e => this.previews[index] = e.target.result);
reader.addEventListener('error', e => this.previews[index] = this.errorImage);
reader.readAsDataURL(file);
});
}
In your markup - wherever you want you previews shown, something like
<span v-for="src in previews">
<img v-if="src && src.length" :src="src"/>
</span>

Remember chosen file and reload it in Filedropjs

I'm using FileDropJS to allow users to choose a local file and upload its content to the application.
I'm looking for a way to "choose" the same file automatically for the user, when the user comes back, without him having to drag & drop the file again every time he uses the application.
Is there an easy way to do it with FileDropJS? I looked into the docs but didn't find anything related.
Current code to allow to choose the file and assign its content to a JavaScript variable:
var file_zone = new FileDrop('file_file', file_options);
file_zone.event('send', function (files) {
files.each(function (file) {
file.readData(
function (str) {
file_content = str;
document.getElementById("file_file_label").innerHTML = '<i style="color:green;" class="fa fa-check-circle"></i> Thank you!';
},
function () { alert('Problem reading this file.'); },
'text'
);
});
});
Thanks!

http 404 error when trying to call web api controller action method from .js file

I am getting Http 404 error on button click when i inspect element in browser.
There is a wallpost.js file in Scripts folder containing logic for knockout, client side view model and data- binding etc.
In this file, reference to the WallPost Api controller is given like this---
var postApiUrl = '/api/WallPost/', commentApiUrl = '/api/Comment/';
and on my view page, there is a container for posting and commenting something like this--
<div class="publishContainer">
<textarea class="msgTextArea" id="txtMessage" data-bind="value: newMessage, jqAutoresize: {}" style="height:3em;" placeholder="what's on your mind?"></textarea>
<input type="button" data-url="/Wall/SavePost" value="Share" id="btnShare" data-bind="click: addPost"/>
now, references to script folder js files are given like this---
#section scripts{
<script src="~/Scripts/jquery.autosize.min.js"></script>
<script src="~/Scripts/knockout-3.3.0.js"></script>
<script src="~/Scripts/wallpost.js"></script>
}
First thing i want to clear that autosize.js is working fine on textarea so, i think path to wallpost.js file is correct as it is similar to autosize.js file.
Now, the problem is i am unable to post the message on button click. I have put the breakpoint at the controller's action method which should be hit on this button click, but thats not get hitted.
From what i am understanding, i think i am unable to use wallpost.js file in the Scripts folder or the route to call controller's action method is wrong So,there is a problem in reference i think.
The button click should hit the action method but it's not.
PLzz suggest me what should i try.I can provide more code if required.
I was following this article.http://techbrij.com/facebook-wall-posts-comments-knockout-aspnet-webapi
My web-api controller action method is like this----
namespace WebApp.Controllers
{
public class WallPostController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
public HttpResponseMessage PostPost(Post post)
{
// post.PostedBy = WebSecurity.CurrentUserId;
post.PostedBy = User.Identity.GetUserId<int>();
post.PostedDate = DateTime.UtcNow;
// post.UserProfile.UserId = WebSecurity.CurrentUserId;
ModelState.Remove("post.PostedBy");
ModelState.Remove("post.PostedDate");
// ModelState.Remove("post.UserProfile.UserId");
if (ModelState.IsValid)
{
db.Posts.Add(post);
db.SaveChanges();
// var usr = db.UserProfile.FirstOrDefault(x => x.UserId == post.PostedBy);
var usr = db.Users.FirstOrDefault(x => x.Id == post.PostedBy);
var ret = new
{
Message = post.Message,
PostedBy = post.PostedBy,
PostedByName = usr.UserName,
//PostedByAvatar = imgFolder + (String.IsNullOrEmpty(usr.AvatarExt) ? defaultAvatar : post.PostedBy + "." + post.UserProfile.AvatarExt),
PostedByAvatar = db.Users.Include(s => s.Files).SingleOrDefault(s => s.Id == post.PostedBy),
PostedDate = post.PostedDate,
PostId = post.PostId
// UserId = usr.UserId
};
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, ret);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = post.PostId }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
I don't know why its not working. it was working fine when i was using simple membership.now, i want to use it with aspnet identity.

File upload with jquery form plugin and mvc 3 is not filling in the target property with my partial view

I'm trying to setup a simple file/image upload for a web app I'm working on. To help, I'm using the jquery form plugin found here: http://jquery.malsup.com/form/
From the examples, it seems that you define where you want your return data to be placed by defining the "target" property.
So the problem is that instead of rendering the partial inside the defined 'target' location, my whole browser is 'posting back' and I get redirected to the individual partials page.
public PartialViewResult BackgroundImageWindow()
{
return PartialView();
}
BackgroundImageWindow.cshtml
<div class="divBGImageLoader">
<form id="FileUploadForm" action='#Url.Action("FileUpload", "SlideShow")' method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input id="UploadFileButton" type="submit" value="Upload" />
</form>
<div id="BGImageTable">
#{Html.RenderAction("BackgroundImageWindowTable");}
</div>
</div>
Which goes here:
public PartialViewResult BackgroundImageWindowTable()
{
DirectoryInfo di = new DirectoryInfo(Server.MapPath("~/Content/uploads"));
List<FileInfo> files = di.GetFiles().ToList();
return PartialView(files); // returns a partial with a table of the uploaded files
}
javascript:
$("#UploadFileButton").live("submit", function(e){
e.preventDefault(); // <- doc file said it needed this
e.stopImmediatePropagation(); // <- uuh just in case
var ajaxSubmitOptions = {
target: $("#BGImageTable"),
beforeSubmit: function () {
//$("#loading").show();
},
success: function (data) {
//$("#loading").hide();
}
};
$(this).ajaxSubmit(ajaxSubmitOptions);
return false; //<- documentation said this was necessary to stop the 'post back'
});
FileUpload Part:
public ActionResult FileUpload(HttpPostedFileBase file)
{
// Verify that the user selected a file
if (file != null && file.ContentLength > 0)
{
// extract only the fielname
var fileName = Path.GetFileName(file.FileName);
// store the file inside ~/App_Data/uploads folder
var path = Path.Combine(Server.MapPath("~/Content/uploads"), fileName);
file.SaveAs(path);
}
// redirect back to the index action to show the form once again
return RedirectToAction("BackgroundImageWindowTable");
}
So like I said previously, this seems to be working except for the fact that the partial is being rendered and displayed like if it was a separate page.
You should connect to form submit event instead of UploadFileButton. Just like this
$("#FileUploadForm").live("submit", function(e){
// do your stuff here
}

Categories