Remove Image option in Edit Form - c#

I want to delete image in edit form and to show the upload file option .How can I achieve this using Ajax since I'm using tab panes for multiple forms.
Here is my code,
Biodata.cshtml
<div class="form-group">
<label class="control-label-staff"><b>Photo</b></label>
#if (Model.ImageFiles != null)
{
foreach (var item in Model.ImageFiles)
{
if (item.Name.Substring(0, 2) == "IM")
{
<span class="control-label-staff">
<img src="~/Documents/EmployeeAttachments/#Request.Query["EmpID"].ToString()/#item.Name" width="70px" height="70px" />
</span><br/>
<a asp-page-handler="RemoveImage" data-ajax="true" data-ajax-method="post" data-ajax-complete="RemoveImageCompleted">Delete</a>
}
}
}
#if (Model.ImageFiles == null)
{
<input type="file" asp-for="StaffPhoto" class="form-control-staff" accept="image/*" style="border:1px solid white;" />
}
</div>
Its not calling the asp-page-handler method. Directly executing the ajax method.
function RemoveImageCompleted(event) {
if (event.responseText != "") {
$("#Biodata").html(event.responseText);
} else {
alert("Image Has Been Deleted Successfully");
$.ajax({
url:rootPath + "/Staff/Onboarding/Biodata",
type: "get",
success: function (result) {
$("#Biodata").html(result);
$('a[href="#Biodata"]').tab('show');
}
})
}
}
This is my asp-page-handler method in BioData.cshtml.cs
public async Task<IActionResult> OnPostRemoveImageAsync()
{
string filename = Request.Form["filename"];
if (filename != null)
{
var Folder = StaffBioData.EmpID.ToString();
string filedel = Path.Combine(_env.WebRootPath, "Documents/EmployeeAttachments", Folder, filename);
FileInfo fi = new FileInfo(filedel);
if (fi != null)
{
System.IO.File.Delete(filedel);
fi.Delete();
}
}
return new OkResult();
}
Any help would be appreciated.Thanks.

Links are GET requests. You cannot post via a link; that is what forms are for. You'd need something like:
#if (Model.ImageFiles != null)
{
foreach (var item in Model.ImageFiles)
{
if (item.Name.Substring(0, 2) == "IM")
{
#*<a asp-page-handler="RemoveImage" data-ajax="true" data-ajax-method="post" data-ajax-complete="RemoveImageCompleted">Delete</a>*#
<form method="post" asp-page-handler="RemoveImage" data-ajax="true" data-ajax-method="post" data-ajax-complete="RemoveImageCompleted">
<input type="submit" value="delete" />
</form>
}
}
}

Related

Blazor doesn't re-render on class change

<div>
<div>
<div class="#(Base64Images.Count == 0 ? "block" : "hidden")">
<label for="file-upload">
<span>Upload a file</span>
<InputFile OnChange="HandleChange" id="file-upload" name="file-upload" class="sr-only" />
</label>
</div>
<div class="#(Base64Images.Count > 0 ? "block" : "hidden")">
#foreach(var image in Base64Images)
{
<img src="#image" />
}
</div>
</div>
</div>
#code {
public IReadOnlyList<IBrowserFile> BrowserFiles { get; protected set; } = new List<IBrowserFile>();
private List<string> Base64Images { get; set; } = new List<string>();
private async Task<bool> HandleChange(InputFileChangeEventArgs e)
{
IReadOnlyList<IBrowserFile> fileList;
BrowserFiles = new List<IBrowserFile> { e.File };
await BrowserFilesToBase64Images();
return true;
}
private async Task<bool> BrowserFilesToBase64Images()
{
foreach(var image in BrowserFiles)
{
if(image != null)
{
var format = "image/png";
var buffer = new byte[image.Size];
await image.OpenReadStream().ReadAsync(buffer);
Base64Images.Add($"data:{format};base64,{Convert.ToBase64String(buffer)}");
}
}
return true;
}
}
So I have this code, it's pretty simple. I want to display a preview of what the use uploads, but the preview must only be displayed after the file was selected. Likewise, I want to hide the input (but not remove it from the DOM) when there is an image loaded. But no matter what I do, Blazor won't re-render.
Base64Images.Count
Changes and I have been able to debug it. The conditions should be hit, but the HTML won't change. Is there any way to tell Blazor to re-render?
I know of StateHasChanged(), but not only that one is supposedly called in after every event, but even calling it multiple times doesn't force the re-render.
You'll have to explain what you want to happen. You have Lists, but when you handle the FileInput's OnChange, you're only getting one File (maybe).
If you want multiple files, then you'll have to set your FileInput like this:
<InputFile OnChange="HandleChange" id="file-upload" name="file-upload" class="sr-only" multiple />
And to get the collection of IBrowserFile objects, this:
BrowserFiles = e.GetMultipleFiles(maxAllowedFiles);
Here's my test code based on what you've given us. It works, so we're missing something obvious.
#page "/Images"
<div class="#(Base64Images.Count > 0 ? "block" : "hidden")">
#foreach (var image in Base64Images)
{
<h4>Images goes here</h4>
<img src="#image" />
}
</div>
#if (!_hasImages)
{
<div>
<InputFile OnChange="#OnInputFileChange" multiple />
</div>
}
else
{
<div>
#foreach (var image in Base64Images)
{
<h4>More Images goes here</h4>
<img src="#image" />
}
</div>
}
<button class="btn btn-dark" #onclick="() => Click()"> Click</button>
#code {
List<string> Base64Images = new List<string>();
private bool _hasImages => Base64Images != null && Base64Images.Count > 0;
void Click()
{
Base64Images.Add("Bye");
}
private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
await Task.Delay(1000);
Base64Images.Add("Bye");
}
}

Session variable returning null

I have a login page and I tried storing some data in my sessions but when I run the project it gives me this error as you see in screenshots:
I tried to debug my code as you see in screenshot and its show me Both No_ and E_mail is null even though I checked my database and those columns. No_ and E_mail both have data:
The Code in Controller:
[HttpPost]
public ActionResult Login(string Mail)
{
using (DataContext db = new DataContext())
{
ED_data_A_S_Contact con = new ED_data_A_S_Contact();
ED_data_A_S_Contact_Business_Relation cb = new ED_data_A_S_Contact_Business_Relation();
var user = from cbr in db.Contact_Business_Relation
join c in db.Contact
on cbr.Contact_No_ equals c.Company_No_ into f
from c in f.DefaultIfEmpty()
//where c.E_Mail == Mail
select new
{
Mail = c.E_Mail
};
if (user != null)
{
Session["No_"] = cb.No_.ToString();
Session["Email"] = con.E_Mail.ToString();
FormsAuthentication.SetAuthCookie(Mail, false);
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("", "Kunde nr er ikke gyldig");
}
}
return View();
}
public ActionResult LoggedIn()
{
if (Session["No_"] != null)
{
return View();
}
else
{
return RedirectToAction("Login");
}
}
Contact_Business_Relation :
public string No_ { get; set; }
Contact:
public string E_Mail { get; set; }
The Code in view:
#model ED_data_A_S_Contact
<div class="login-wrap">
<div class="login-html">
<input id="tab-1" type="radio" name="tab" class="sign-in" checked><label for="tab-1" class="tab">Log ind</label>
<input id="tab-2" type="radio" name="tab" class="sign-up"><label for="tab-2" class="tab"></label>
<form class="login-form" method="POST" enctype="multipart/form-data" action="/Account/Login/">
#*#Html.AntiForgeryToken()*#
<div class="sign-in-htm">
<div class="group">
<label for="No_" class="label">Kunde ID</label>
<input style="color:black;" id="Email" name="Mail" value="" required="" type="email" placeholder="Kunde ID ..." class="input">
<button style="float: right;margin-top: -36px; background: transparent; border: none;margin-right: 11px;" type="button" id="eye">
<img src="https://cdn0.iconfinder.com/data/icons/feather/96/eye-16.png" alt="eye" />
</button>
#*#Html.ValidationMessageFor(u => u.CustomerID)*#
</div>
<div class="group">
<input type="submit" class="button" value="Log på">
</div>
<span style="color:#dadada">#*#Html.ValidationSummary(true)*#</span>
<div class="hr"></div>
<div class="foot-lnk">
<a target="_blank" href="#">Problem med login?</a>
</div>
</div>
</form>
</div>
</div>
Can anyone direct me in the right direction? thx
ED_data_A_S_Contact_Business_Relation cb = new ED_data_A_S_Contact_Business_Relation();
You don't actually seem to set the properties of this object anywhere before accessing them. All you do is new the object. All the properties have their default values.
Perhaps you should be accessing user.Mail? In which case you should also set the other properties also.
Try this:
// Populate the user variable so we can use it below to set session variables
var query = from cbr in db.Contact_Business_Relation
join c in db.Contact
on cbr.Contact_No_ equals c.Company_No_ into f
from c in f.DefaultIfEmpty()
where c.E_Mail == Mail
select new
{
Mail = c.E_Mail,
No = c.No // Or whatever the relevant property is in c or cbr
};
var user = query.FirstOrDefault();
if (user != null)
{
Session["No_"] = user.No.ToString();
Session["Email"] = user.Mail.ToString();
FormsAuthentication.SetAuthCookie(user.Mail, false);
return RedirectToAction("Index");
}

MVC PartialView how to stay in same page after using PartialView to upload?

I have three page, It all contain a PartialView that is a member data info panel.
That PartialView can change Photo using Html.BeginForm.
But I face the problem with when I Submit Photo, It can't return to same page.
How to solved it ?
Code:
View(Page,have three diffrent page , but all have same PartialView):
<div>Page 1</div>
<div class="sidebar">
#Html.Action("_MemberInfoPartial")
</div><!-- END sidebar-->
<div>blah blah ... </div>
View(Partial):
<figure class="cropper">
<a>#Model.UserName</a>
<img src="#Model.Image" class="photo">
<figcaption>Select Pic</figcaption>
#using (Html.BeginForm("UploadIcon", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<input type="file" name="file" id="file" class="temp-icon-file" />
<input type="submit" name="submit" value="Submit" class="temp-icon-submit" />
}
<script>
$(function () {
$('.cropper figcaption a').click(selectFile);
$('.temp-icon-file').change(uploadFile);
});
function selectFile() {
$('.temp-icon-file').click();
}
function uploadFile() {
var val = $('.temp-icon-file').val().toLowerCase().split('.');
if (val.length > 0) {
var ext = val[val.length - 1];
if (ext === 'jpg' || ext === 'png') {
$('.temp-icon-submit').click();
return;
}
}
}
</script>
</figure>
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadIcon(HttpPostedFileBase file)
{
if (file != null && file.ContentLength > 0)
{
//Upload Image
}
else
TempData["TempMessage"] = "Please Select Picture! (jpg/png)";
return RedirectToAction("Page1") <--How to return to same page(The Page I click upload, it can be page1 or 2 or 3)?
}
if you pass current action name when calling child action:
#Html.Action("_MemberInfoPartial", new { parentAction = ViewContext.RouteData.Values["action"] })
and in your child action, store it in ViewData:
public ActionResult _MemberInfoPartial(string parentAction)
{
//...
ViewBag.ParentAction = parentAction;
//...
}
to render parent action in a hidden field, for example:
#{
string parentAction = ViewBag.ParentAction;
}
#using (Html.BeginForm("UploadIcon", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<input type="file" name="file" id="file" class="temp-icon-file" />
<input type="submit" name="submit" value="Submit" class="temp-icon-submit" />
#Html.Hidden("returnAction", parentAction)
}
you can use parent action upon form submit:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadIcon(HttpPostedFileBase file, string returnAction)
{
if (file != null && file.ContentLength > 0)
{
//Upload Image
}
else
TempData["TempMessage"] = "Please Select Picture! (jpg/png)";
return RedirectToAction(returnAction);
}
Pass a value to your controller to determine on what page you need to return.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadIcon(HttpPostedFileBase file, int returnId)
{
if (file != null && file.ContentLength > 0)
{
//Upload Image
}
else
TempData["TempMessage"] = "Please Select Picture! (jpg/png)";
if(returnId == 1)
return RedirectToAction("Page1");
//and so on..
}

How to upload multiple files asynchronously in ASP.NET MVC (C#) using Progress Bar

I am building an MVC based ASP.NET application. One of the functionalities should be to be able to upload files asynchronously using a progress bar.
I've had success with uploading files without the progress bar. The code below does that.
View Code:
<input class="file" type="file" name="file" id="file" />
<input type="submit" name="submit" value="Upload" />
Controller Code:
public ActionResult Upload(){
return View();
}
[HttpPost]
public ActionResult Upload(Resource resource)
{
try
{
if (resource.File.ContentLength > 0)
{
var fileName = Path.GetFileName(resource.File.FileName);
var path = Path.Combine(Server.MapPath("~/Content/Resources"), fileName);
resource.File.SaveAs(path);
}
}
catch (Exception e)
{
Console.WriteLine("Cannot upload file. Exception of type : {0}", e.ToString());
}
return RedirectToAction("Upload");
}
This code works absolutely fine. With slight modifications, I am even able to upload multiple files. But, even though I've tried finding it, I am not able to upload files using a progress bar.
Any help is appreciated.
This is how I do it - the controller code is much the same, but the client has some javascript in it to monitor and update progress of the ajax posting. The UI Html is like this:
<div id="uploadDetails" class="form-group">
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-primary btn-file">
Browse… <input type="file" name="file" id="file" />
</span>
</span>
<input type="text" id="filename" class="form-control fullwidth" readonly />
<span class="input-group-btn">
<button class="btn btn-primary" type="button" id="uploadFile"><span class="glyphicon glyphicon-upload"></span> Upload File </button>
</span>
</div>
</div>
And the javascript for the upload like this:
$(document).on('click', '#uploadFile', function (e) {
var fileElement = document.getElementById('file');
var file = fileElement.files[0];
var formData = new FormData();
formData.append("filename", fileElement.files[0].name);
formData.append("id", '#Model.SharedIP.Id');
formData.append("file", file, fileElement.files[0].name);
var html = $('#uploadFile').html();
$('#uploadFile').html('Uploading...');
$.ajax({
url: "#Url.Action("UploadFile", "SharedIP")",
type: "POST",
data: formData,
processData: false, // tell jQuery not to process the data
contentType: false, // tell jQuery not to set contentType
xhr: function(){
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
$('#uploadFile').html('Uploading... ' + Math.round((evt.loaded / evt.total) * 100) + '%');
}
else $('#uploadFile').html('hmmm');
}, false);
return xhr;
},
success: function (results) {
updateFilesList();
$('#uploadFile').html(html);
fileElement.files = [];
var control = $('#file');
control.replaceWith(control.clone(false));
$('#filename').val("")
},
error: function (xhr, ajaxOptions, thrownError) {
$('#uploadFile').html(html);
alert(xhr.responseText);
}
});
});
For completeness, here's the Controller signature, it's .net Core RC1 so might not work in your target framework, but you will get the idea.
[HttpPost]
public IActionResult UploadFile(string filename, Guid id, IFormFile file)
{
IPFile ipfile = new IPFile()
{
ContentType = file.ContentType,
DateUploaded = DateTime.Now,
Filename = filename,
SharedIPId = (id == Guid.Empty ? (Guid?)null : id),
Id = Guid.NewGuid(),
UploadedBy = User.Alias(),
};
ipfile = FileManager.AddFileFromStream(User.Alias(), ipfile, file.OpenReadStream());
return Ok(ipfile);
}
Hope that answers your question.
[EDIT] Just realised this isn't a "progress bar" - but it's got all the workings and % display - to put a progress bar in, you'd just apply CSS to an element that renders the % graphically for you - see posts like http://www.w3schools.com/bootstrap/bootstrap_progressbars.asp for examples.
Here is the code that I have tried. It's a bare minimum code but works as expected. It still has some bugs and I would appreciate if someone could make it bug free.
Some bugs:
Progress bar does not reset on a new file upload.
Add a button to do the upload (I can do it myself as well).
Model Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace NewDeploymentsTesting.Models
{
public class UploadFilesResult
{
public string Name { get; set; }
public int Length { get; set; }
public string Type { get; set; }
}
}
Controller Code:
using NewDeploymentsTesting.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace NewDeploymentsTesting.Controllers
{
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
[HttpPost]
public ContentResult UploadFiles()
{
var r = new List<UploadFilesResult>();
foreach (string file in Request.Files)
{
HttpPostedFileBase hpf = Request.Files[file] as HttpPostedFileBase;
if (hpf.ContentLength == 0) continue;
string savedFileName = Path.Combine(Server.MapPath("~/Content/Resource"), Path.GetFileName(hpf.FileName));
hpf.SaveAs(savedFileName);
r.Add(new UploadFilesResult()
{
Name = hpf.FileName,
Length = hpf.ContentLength,
Type = hpf.ContentType
});
}
return Content("{\"name\":\"" + r[0].Name + "\",\"type\":\"" + r[0].Type + "\",\"size\":\"" + string.Format("{0} bytes", r[0].Length) + "\"}", "application/json");
}
}
}
View Code:
#{Layout = null;}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Uploading Files</title>
<link href="~/Content/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap/bootstrap-theme.css" rel="stylesheet" />
<link href="~/Content/jquery.fileupload.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/jquery.ui.widget.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/jquery.fileupload.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('#fileupload').fileupload({
dataType: 'json',
url: '/Home/UploadFiles',
autoUpload: true,
done: function (e, data) {
$('.file_name').html(data.result.name);
$('.file_type').html(data.result.type);
$('.file_size').html(data.result.size);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('.progress .progress-bar').css('width', progress + '%');
});
});
</script>
</head>
<body>
<div class="container">
<span class="btn btn-success fileinput-button">
<i class="glyphicon glyphicon-plus"></i>
<span>Add Files ...</span>
<input id="fileupload" type="file" name="files[]" multiple />
</span><br />
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="sr-only">0% Complete</span>
</div>
</div><br />
<div class="file_name"></div><br />
<div class="file_type"></div><br />
<div class="file_size"></div><br />
</div>
</body>
</html>
Here is what it looks like on the browser window.

ASP.NET WebAPI change file name?

I am trying to change the file name of images to the value that I posted in the input box username. The files are getting uploaded to the server and also, after overriding GetLocalFileName the file name is changed from "BodyPart_(xyz)" to the original one. How do I rename them to the value that I provided in the input box?
<form name="form1" method="post" enctype="multipart/form-data" action="api/poster/postformdata">
<div class="row-fluid fileform">
<div class="span3"><strong>Username:</strong></div>
<input name="username" value="test" type="text" readonly/>
</div>
<div class="row-fluid fileform">
<div class="span3"><strong>Poster:</strong></div>
<div class="span4"><input name="posterFileName" ng-model="posterFileName" type="file" /></div>
</div>
<div class="row-fluid fileform">
<div class="span8"><input type="submit" value="Submit" class="btn btn-small btn-primary submitform" /></div>
</div>
</form>
I have stored the value that I received in the newName variable but I am confused on how to rename the file in the server.
public async Task<HttpResponseMessage> PostFormData()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
string root = HttpContext.Current.Server.MapPath("~/App_Data");
var provider = new MultipartFormDataStreamProvider(root);
try
{
await Request.Content.ReadAsMultipartAsync(provider);
// Show all the key-value pairs.
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
Trace.WriteLine(string.Format("{0}: {1}", key, val));
newName = val;
}
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (System.Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
public class MyMultipartFormDataStreamProvider : MultipartFormDataStreamProvider
{
public MyMultipartFormDataStreamProvider(string path)
: base(path)
{
}
public override string GetLocalFileName(System.Net.Http.Headers.HttpContentHeaders headers)
{
string fileName;
if (!string.IsNullOrWhiteSpace(headers.ContentDisposition.FileName))
{
fileName = headers.ContentDisposition.FileName;
}
else
{
fileName = Guid.NewGuid().ToString() + ".data";
}
return fileName.Replace("\"", string.Empty);
}
}
One way is to override the ExecutePostProcessingAsync method like the following:
public override async Task ExecutePostProcessingAsync()
{
await base.ExecutePostProcessingAsync();
// By this time the file would have been uploaded to the location you provided
// and also the dictionaries like FormData and FileData would be populated with information
// that you can use like below
string targetFileName = FormData["username"];
// get the uploaded file's name
string currentFileName = FileData[0].LocalFileName;
//TODO: rename the file
}

Categories