Send an image to an api controller with angularjs - html

I have this on my html page
<div class="form-group col-xs-7 col-lg-6">
<label>Background image</label>
<input type="file" name="background_image" id="background_image" ng-model="selectedLayout.background_image" class="form-control" />
<button class="btn btn-primary" ng-click="save(selectedLayout)">Change background image</button>
</div>
This is what I have in controller
$scope.save = function (selectedLayout) {
$http({
method: 'POST',
url: 'api/LayoutSettings/PostImage',
data: selectedLayout.background_image,
headers: {
'Content-Type':'image/jpeg'
}
});
};
And this is my method in the api controller named LayoutSettings
public async Task<HttpResponseMessage> PostImage()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
I don't know why when i actual press the change background image I send an empty object. Someone have some idea how i can actual pass the image there? Thanks.

ng-model is not supported by input[file] type, there is a note in the Angular docs about it:
Note: Not every feature offered is available for all input types.
Specifically, data binding and event handling via ng-model is
unsupported for input[file].
Try this instead.

Related

Angular: Re-render asynchronous data in image tag

I am using Angular to fetch user profile picture from backend(Node.js/Express). Everything is working perfectly except for one thing. The Angular does not re-render the HTML that displays the profile picture incase, the user has updated his picture or if no picture is present and user uploads his first image. As expected, the Angular is rendering the HTML only once and isn't re-rendering again. I don't know how can I wait for asynchronous data in HTML as I am directly targeting an endpoint in HTML instead of TS.
Here's my code:
userProfile.component.html
<div class = "imgClass">
<img class = "img-thumbnail rounded-circle imgclass"
src="http://localhost:3000/api/getProfilePhoto?id={{cookieData}}">
//angular is sending request to the above endpoint to fetch the image only once at the time
application starts or user logs in. How can I send a request again?
<div class="middle">
<div class="text"><button type="button" name="button" (click) = "selectImage()" class = "btn
btn-outline-primary"> <i class="bi bi-plus"></i> </button></div>
<input type="file" id="imgUpload" (change) = "handleImageInput($event.target.files)">
</div>
</div>
userProfile.component.ts
selectImage()
{
document.getElementById('imgUpload').click();
}
handleImageInput(files: FileList)
{
this.imageUpload = files.item(0);
this.uploadImage();
}
uploadImage()
{
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {params, responseType: "text"})
.subscribe(responseData => {
this.imageChanged = true; //I have tried using this as *ngIf in HTML but it is not working either
}
,error => {
console.log("Image uploading failed" + error.message);
})
}
Does anybody know how can I send the request to an endpoint in HTML once user changes/uploads his first picture?
You need to trigger the image fetch request for each update/upload requests. Or you could adjust the backend to return the image data from the update/upload requests.
Option 1: manually fetch image for each update/upload requests
Use RxJS switchMap operator to switch to image fetch request after the uploading has completed. It'll not be fetched if the uploading failed.
profileImage: any;
selectImage() {
document.getElementById('imgUpload').click();
}
handleImageInput(files: FileList) {
this.imageUpload = files.item(0);
this.uploadImage();
}
uploadImage() {
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {
params,
responseType: "text"
}).pipe(
tap(null, error => console.log("Image uploading failed" + error.message)),
switchMap(_ => this.http.get(`http://localhost:3000/api/getProfilePhoto?id${this.cookieData}`))
).subscribe(
image => {
this.profileImage = image;
},
error => {
console.log("Image fetching failed" + error.message);
}
);
}
<img class="img-thumbnail rounded-circle imgclass" [src]="profileImage">
Option 2: Return the image from upload/update request
Adjust the backend to return the image data from the Upload POST request.
profileImage: any;
uploadImage() {
const formData = new FormData();
const params = new HttpParams().set('id', sessionStorage.getItem('cookie'));
formData.append("file", this.imageUpload, this.imageUpload.name);
this.http.post('http://localhost:3000/api/updateImage', formData, {
params,
responseType: "text"
}).subscribe(
image => {
this.profileImage = image;
},
error => {
console.log("Image uploading failed" + error.message);
}
);
}
<img class="img-thumbnail rounded-circle imgclass" [src]="profileImage">
As a sidenote, using document.getElementById() in Angular will search the whole DOM, not just the individual component. In relatively complex apps, it might lead to performance issues. Instead try to use an event handler or if it's not possible, use Angular ViewChild with a template reference parameter to get an element from the current component's DOM.
if the webservice resolving the image url returns an Observable, you can make the call from typescript like below
imageData$: Observable<number>;
getImage(id): Observable<string> {
this.imageData$=http.get(url?id=<some_id>);
return this.imageData$
}
and the adding async pipe on it
<img class = "img-thumbnail rounded-circle imgclass" [src]="imageData$ | async">
Basically The async pipe subscribes to an Observable or Promise and
returns the latest value it has emitted. When a new value is emitted,
the async pipe marks the component to be checked for changes. When the
component gets destroyed, the async pipe unsubscribes automatically to
avoid potential memory leaks.

Controller Void Method On Button Click Using Ajax. ASP.NET

So I have a .ASP MVC Web Application project. I want to run a void method from the controller class when I press a button using AJAX. No variable input or output data needed. I just want to create a pdf file and save it on my local machine.
Right now, nothing at all happens when I click the button. I don't think the ajax script works, 0 connection.
This is my Controller method:
[HttpPost]
public void Test()
{
string dok = System.IO.File.ReadAllText("C:\\Users\\axel\\Desktop\\Repo\\Cert\\employee_regular.html");
var Renderer = new IronPdf.HtmlToPdf();
var HtmlTemplate = dok;
var Pdf = Renderer.RenderHtmlAsPdf(HtmlTemplate);
Pdf.SaveAs("C:\\Users\\axel\\Desktop\\Repo\\Cert\\Arbetsgivarintyg_vanlig_heltid.pdf");
}
This is my Index.cshtml file
#{
ViewBag.Title = "Home Page";
}
<div class="row">
<div class="col-md-12">
<h2>Request employement certificate</h2>
<input type="button" onclick="BtnClick()" value="Click me" />
</div>
</div>
<script>
function BtnClick() {
$ajax({
url: "/Home/Test",
method: "POST",
success: function () {
alert("ok");
},
error: function () {
alert("not ok")
}
})
}
</script>
Really happy for any help
Well there can be several reasons why your code is not working.
First Make sure you are actually able to make a call to a function, Just simply add simple alert message before calling the ajax and see if the alert triggers.
The second thing is to validate url replace the hardcoded url and add url using URL helper.
I would recommend you to make a function as JsonResult Instead of Void, because an exception can happen when creating pdf. [This change is optional but I do recommend it]
So after all the changes your code would look something like this
#{
ViewBag.Title = "Home Page";
}
<div class="row">
<div class="col-md-12">
<h2>Request employement certificate</h2>
<input type="button" onclick="BtnClick()" value="Click me" />
</div>
</div>
<script>
function BtnClick() {
$ajax({
alert("Funciton is working"); // change confirm function is working
url: "#Url.Action("Test","Home")", // change using Url Helper to create valid URL
method: "POST",
success: function (data) {
if (data == true)
{
alert("pdf created sucessfully ok");
}
else
{
alert("exception happend when creating pdf not ok");
}
},
error: function () {
alert("not ok")
}
})
}
</script>
Your Back End would look something like this
[HttpPost]
public JsonResult Test()
{
try {
string dok = System.IO.File.ReadAllText("C:\\Users\\axel\\Desktop\\Repo\\Cert\\employee_regular.html");
var Renderer = new IronPdf.HtmlToPdf();
var HtmlTemplate = dok;
var Pdf = Renderer.RenderHtmlAsPdf(HtmlTemplate);
Pdf.SaveAs("C:\\Users\\axel\\Desktop\\Repo\\Cert\\Arbetsgivarintyg_vanlig_heltid.pdf");
return Json(true, JsonRequestBehavior.AllowGet);
}
catch(Exception ex) {
return Json(false, JsonRequestBehavior.AllowGet);
}
}

get html 5 date input field and pass to .net controller

On my razor page, I have a simple date picker that looks like this:
<input type="date" name="lessonsStart">
How would I go about getting the value of that and sending it to my controller?
Whenever I send data to my controller from a razor page, the format always looks something like this:
<a asp-action="LessonIndex" asp-route-id="#item.Id">#Html.DisplayFor(modelItem => item.Name)</a>
which sends an "item.Id" to my controller called LessonIndex().
So I'm not sure how I'd get the date value and send it.
The controller looks like this:
public IActionResult LessonIndex(datetime startDate) {
var response = getLessons(startDate);
return response.Results;
}
Is there a specific format I need to use?
Note that the date is not used in a model, it just needs to be sent to a controller.
Thanks!
Assuming this is related to mvc the controller would have a method associated with the post that you would perform to get the data from the form back to the controller. This uses javascript to post data to your LessonIndex() method.
<!--top of your page.-->
#inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
#functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="date" id="lessonStart" name="lessonStart" />
<input type="Submit" id="PostButton" name="PostButton" Value="Go" />
#section Scripts{ // razor section at the bottom of mvc page 'cshtml'.
<script type="javascript">
$(function(){
$("#PostButton").click(function(){
var url = '#Url.Action("LessonIndex", "Lesson")'; //assuming controller is named Lesson
var date= new Date(this.value).ToDateString();
$.ajax({
url: url,
type: "POST",
data: "lessonStart=" + date,
headers:{
"RequestVerificationToken": '#GetAntiXsrfRequestToken()'
},
success: function(response){
console.log(response);
},
error: function(e){
console.log(e.error);
}
});
});
}
</script>
}
this also assumes that the method looks like this
public class LessonController : Controller{
[HttpPost]
[AutoValidateAntiforgeryToken]
public IActionResult LessonIndex(DateTime lessonStart){
var response = getLessons(lessonStart);
return View(response.results);
}
}
" Note that the date is not used in a model, it just needs to be sent to a controller. "
You could use the ajax to pass the date as QueryString to the method in the controller.
Here is the test example
<input type="date" name="lessonsStart" id="lessonsStart">
#section Scripts
{
<script type="text/javascript">
$("#lessonsStart").change(function () {
var inputDate = new Date(this.value).toDateString();
$.ajax({
type: "post",
url: "/ControllerName/lessonindex?startdate=" + inputDate,
success: function () { }
});
});
</script>
}
The method in controller
[HttpPost]
public IActionResult LessonIndex(DateTime startDate)
{
return Json(startDate);
}
<div class="demo-section k-content">
<h4>Remind me on</h4>
#(Html.Kendo().DateTimePicker()
.Name("datetimepicker")
.Value(DateTime.Now)
.HtmlAttributes(new { style = "width: 100%", title = "datetimepicker" })
.DateInput()
)
</div>

MVC5 controller not getting file from HTML file input

I'm trying to simply allow a user to upload a file.
I have a simple begin form that contains a file element as shown below:
#using (Html.BeginForm("LoadData", "Input", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div style="width:23%; display:inline-block;">
<label>Select Type:</label>
<select name="UploadType">
<option value="First">First</option>
<option value="Second">Second</option>
</select>
</div>
<div style="width:43%; display:inline-block;">
<input type="file" name="files1" id="files1" />
</div>
<div style="width:33%; display:inline-block;">
<input type="submit" value="Upload"/>
</div>
}
The controller is :
[HttpPost]
public ActionResult LoadData(string UploadType, HttpPostedFileBase file1)
{
if(file1 != null && UploadType != null)
{
Console.WriteLine(file1.FileName);
Console.WriteLine(UploadType);
}
}
Everything displays and works on the site but when it posts back the file is null. I've looked at many google results including:
Binding HttpPostedFileBase using Ajax.BeginForm
MVC 4 Razor File Upload
http://www.aurigma.com/upload-suite/developers/aspnet-mvc/how-to-upload-files-in-aspnet-mvc
and more. they all say my stuff is correct. As long as the names match on the file input and the controller param, it should work. But it's not.
I've tried naming it file, files, and now file1 but no mater what I call it, it comes back null.
What am I doing wrong? I even tried checking the Request.Files but that says it has a count of 0.
I ended up using javascript to handle the files instead. Here's the working code:
Javascript (it allows multiple files now):
function SendData() {
var formData = new FormData(document.querySelector('UploadForm'));
for(var i = 0; i < $('#file')[0].files.length; i++)
{
formData.append('files', $('#file')[0].files[i]);
}
formData.append('samplevalue', $('#samplevalue').val());
var url = $('#baseUrl').val() + 'Input/LoadData';
$.ajax({
url: url,
type: 'POST',
data: formData,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
success: function (data) {
// your logic....
},
error: function(data)
{
// logic....
}
});
}
The controller then accepts
public string LoadData(string samplevalue, HttpPostedFileBase[] files)
{
}
Of course the trick is the javascript. I still don't know why the form doesn't work normally but this works perfectly. :)
Your file input is named files1, but your action param is file1 (no s).
#using (Html.BeginForm("MethodName", "ControllerName", FormMethod.Post,
new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<input type="file" name="ImgUploader" id="ImgUploader" />
<input type="submit" value="Create" class="btn btn-default" />
}
**Your Controller**`[HttpPost]
public ActionResult Create()
{
HttpPostedFileBase file = Request.Files["ImgUploader"];
}

How to send a list of selected checkboxes from view to controller

I have been trying to work out how I can get the list of selected checkboxes to work using an ActionLink. I think I need to do something clientside with JavaScript but cannot find the relevant code.
The following code works perfectly using a submit button, posting back the selected id's as an array of id's, but I need to have this on a page with other buttons.
// the view
#foreach (var station in Stations)
{
<input type="checkbox" name="selected" value="#station.StationId" />
}
<input type="submit" value="Save" />
//Controller stub
public ActionResult Action(string [] selected)
I have been stuck on this for hours, so maybe I am looking at this the wrong way.
PS. My first post after many many hours reading and learning here.
SomeButtons or links to post checkboxlist values
Post
//or buttons, helpers and any elements to trigger ajax post...
CheckboxList:
<div id="MyDiv">
#foreach (var station in Stations)
{
<input type="checkbox" name="selected" value="#station.StationId" />
}
</div>
Scripts:
$(document).ready(function() {
$('#someButton').click(function() {
var list = [];
$('#MyDiv input:checked').each(function() {
list.push(this.name);
});
// now names contains all of the names of checked checkboxes
// do something with it for excamle post with ajax
$.ajax({
url: '#Url.Action("Action","Contoller")',
type: 'POST',
data: { Parameters: list},
success: function (result) {
alert("success")!
},
error: function (result) {
alert("error!");
}
}); //end ajax
});
});
Controller:
public ActionResult Action(string [] Parameters)
if I got it right :)
Looks like you are not looking for AJAX post. The easiest way to tackle this is to wrap it in the form and call submit function. Here is what your code should look like:
#using(Html.BeginForm("uraction", "urcontroller", FormMethod.Post, new { id = "formId" })) {
foreach(var station in Stations) {
<input type="checkbox" name="selected" value="#station.StationId" />
}
}
Post
<script>
$(document).ready(function() {
$('#postBtn').click(function() {
$('#formId').submit();
}
}
</script>