I have a view that contains a submit button. When that submit button is clicked some code runs a process. I want to return a text message to a label on the view that will let the user know that their submission was successful or there was an error.
I've searched around and I have found many examples about labels but I haven't come across one that shows me how to do what I want.
My Controller:
public ActionResult Import()
{
//Some code that runs a process
//Need to know what code will return "Import was Successful" or "Erroring Importing"
return RedirectToAction("Import")
}
My View:
#{
ViewBag.Title = "Import";
}
<h2>Import</h2>
#using (Html.BeginForm("Importexcel", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr><td>Import Files</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr>
<tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr>
**<tr><td>#Html.Label(returned results)</td></tr>** // Need to know how to do this
</table>
}
In your view:
#using (Html.BeginForm("Importexcel", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr><td>Import Files</td><td><input type="file" id="FileUpload1" name="FileUpload1" /></td></tr>
<tr><td></td><td><input type="submit" id="Submit" name="Submit" value="Submit" /></td></tr>
**<tr><td>#Html.Label(returned results)</td></tr>** // Need to know how to do this
</table>
#ViewBag.Message
}
In your controller:
[HttpPost]
public ActionResult Import(){
//Some code that runs a process
//Need to know what code will return "Import was Successful" or "Erroring Importing"
if(something){
ViewBag.Message = "Import Failed";
}
else
{
ViewBag.Message = "Import Successful";
}
return View();
}
Try and give that a shot.
You can always pass either a key to a look-up table of messages or the message itself via the query string. Here's an example:
Controller Action
public ActionResult Import(string message = null)
{
// Detect presence of message (i.e. !String.IsNullOrWhiteSpace(message)) and show it.
// Additional logic after this...
return RedirectToAction("Import", "YourControllerNameHere", new { message = "Your message here..." });
}
Then it's just a matter of wiring up your model or ViewModel in the Import view so it displays the appropriate message.
Related
I am trying to build a simple CMS which allows the author to upload files (specifically images but the file type is not really important for now).
The upload of the file is working fine. However I want to provide the ability to list and subsequently delete a file (maybe later multiple files but for now a single file at a time is fine).
I have looked around the net. I see plenty of examples using EF to store the location of the file in a DB because they have permissions and roles etc. While that is something I may need way off in the future, its not a layer of complexity I am willing to add right now.
All I want is to simply press a delete link (just as though you are deleting a record in a DB). To trigger an action which calls a delete confirmation view. Then on that view, a delete button to actually delete the file and return the user to the list. Below is my code so far:
This would be the view that lists the files:
#model IEnumerable<FileInfo>
#{
ViewBag.Title = "File List";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Upload", "Upload")
</p>
<table class="table">
<tr>
<th>File Name</th>
<th>Actions</th>
</tr>
#foreach (FileInfo file in Model)
{
<tr>
<td>#file.Name</td>
<td>#Html.ActionLink("Delete", "Delete", new { fileName = #file.Name })</td>
</tr>
}
</table>
I wont show the controller for this view as it's relatively simple and not where I am having the problem (I think). I only showed this so you could see the delete link and tell me if there is anything wrong.
Below is the delete confirmation view:
#model FileInfo
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.FullName)
</dt>
<dd>
#Html.DisplayFor(model => model.FullName)
</dd>
</dl>
#using (Html.BeginForm("Delete", "FileManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-actions no-color">
#Html.ActionLink("Back to list of views", "Index", null, new { #class = "btn btn-success" })
|
#*#Html.ActionLink("Delete", "Delete", null, new { #class = "btn btn-danger" })*#
<input type="submit" value="Delete file" formaction="Delete" formmethod="delete" class="btn btn-danger" />
</div>
}
Below are the two Delete actions (GET and POST / DELETE)
// GET: FileManagement/Delete/filename
public ActionResult Delete()
{
return View();
}
// POST: FileManagement/Delete/filename
[HttpDelete]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
var path = Path.Combine(Server.MapPath("~/UserFiles"), fileName);
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
else
return HttpNotFound();
return RedirectToAction("Index");
}
I don't have view models as I am not connecting to a database (yet). The files are just uploaded to the folder ~/UserFiles/someFileName.ext and the full path is got through appending this to the server.mappath in the normal way.
The problem I am having is getting the file name into the delete confirmation view, and also into the delete button which would pass it to the delete action to do the job.
Thanks for any help.
In your main view (I assume that Index.cshtml), you correctly generate a query string value for the fileName, but the GET method does not have a parameter to accept it. It would need to be
// GET: FileManagement/Delete/filename
public ActionResult Delete(string fileName)
and in that method you would need to initialize a new FileInfo class based on the fileName and pass that model to the view.
The next issue is that your form in the confirm page does not pass the file name back to the POST method, but that raises another issue in that you cannot have a GET and POST method with the same signatute, so you would need to change the name of one of the methods, for example
[HttpGet]
public ActionResult ConfirmDelete(string fileName)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
and in the confirm delete page, change the form to
#using (Html.BeginForm("Delete", "FileManagement", new { fileName = Model.Name })) // enctype not required
{
#Html.AntiForgeryToken()
<input type="submit" value="Delete file" class="btn btn-danger" />
}
However, you can greatly improve performance by generating the form in the Index view and displaying a confirm dialog (the GET method is no longer required)
#foreach (FileInfo file in Model)
{
....
#using(Html.BeginForm("Delete", "FileManagement", new { fileName = file.Name }))
{
#Html.AntiForgeryToken()
<input type="submit" value="delete" />
}
}
and adding a script to display the dialog
$('form').submit(function() {
return conform("Are your sure .... ");
});
which will display the browsers javascript confirm dialog. You can further enhance the UI by using a jquery plugin for the confirm dialog (or implement your own, as explained in this article)
You should also consider using ajax to submit the form (and in the success callback, remove the button and its associated table row). A typical implementation might look like
#foreach (FileInfo file in Model)
{
<tr>
<td>#file.Name</td>
<td>
<form class="deleteform">
#Html.AntiForgeryToken()
<input type="hidden" name="fileName" value="#file.Name" />
<input type="submit" value="delete" />
</form>
</td>
</tr>
}
var url = '#Url.Action("Delete", "FileManagement")';
$('.deleteform').submit(function() {
var formData = $(this).serialize();
var row = $(this).closest('tr');
$.post(url, formData, function(response) {
if (response) {
row.remove();
} else {
// Oops - display message?
}
}).fail(function (response) {
// Oops
});
return false; // cancel the default submit
});
and the controller method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
.... // delete the file
return Json(true); // indicate success
// or return Json(null); to indicate failure
}
I have list of resumes on which jobseeker can add note and send message to each of them. So I created partial view of resume. I used Ajax.Beginform method in partial views. On partial view there is submit option. Now when I call a specific resume partial view it calls the action and perform the job but not single time it repeats for each resume item. So why is the action called repeatedly? My View is here
#model NoteViewModel
<script src="~/Content/scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<div class="app-tab-content" id="two-1">
#using (Ajax.BeginForm("AddNote","Employer",new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "result" }))
{
if(#Model!=null)
{
<input type="text" name="note" />
<input type="hidden" value="#Model.Res_id" name="res" />
<input type="hidden" value="#Model.Job_id" name="job" />
#*<button type="submit" value="AddNote"></button>*#
<input type="submit" id="AddNote" value="Add Note" />
}
}
<div id="result">
#if(ViewBag.NoteMessage!=null)
{
<p>ViewBag.NoteMessage</p>
}
</div>
</div>
Here is an action method
public ActionResult AddNote(string note, int? res, int? job)
{
jpc_resume_job jr = db.jpc_resume_job.Where(m => m.job_id == job && m.resume_id == res).FirstOrDefault();
if (ModelState.IsValid)
{
jr.note = note;
db.Entry(jr).State = EntityState.Modified;
db.SaveChanges();
ViewBag.NoteMessage = "Note Added Successfully";
return PartialView("Addnote");
}
ViewBag.NoteMessage = "Note Not Added Successfully";
return PartialView("Addnote");
}
I am calling this in searchresume view like this:
Foreach(var item in resume)
{
#Html.Partial("Addnote");
}
An image is attached for what exactly I want
I am facing some problem in MVC
Inside view I have 2 buttons, one is for final submit and the other is for adding dynamic content to the view. Again both are used to post the form. I wanted to know how these would be used in controller.
example
If I click final submit, it will redirect to some view or any other operation and also if I click add button in the same view I want to return to the same view.
note: I am using both buttons to post the same action.
<input type="submit" name="actionBtn" value="add value" />
<input type="submit" name="actionBtn" value="finalsubmit" />
in Action
public ActionResult YourPostAction(string actionBtn)
{
if(actionBtn == "Add Value")
{
}
else if(actionBtn == "finalSubmit")
{
}
}
Another way if you want ( You have to play with name but different way)
#using (Html.BeginForm())
{
<input type="hidden" name="actionName" id="hdnAction" />
<input type="submit" value="test" name="actionBtn" onclick="setThis('test')" />
<input type="submit" value="test1" name="actionBtn" onclick="setThis('test1')"/>
}
<script language="javascript">
function setThis(obj) {
document.getElementById('hdnAction').value = obj;
}
</script>
In controller action
[HttpPost]
public ActionResult Index(string actionName)
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
I'm working on asp.net mvc 3 application. I'm implementing a razor view which have tow main functions - to build/display form based on a data from a data base and to show images related to this form in a custom (made by me) image gallery that allows upload and delete of image.
So generally this is my view with both forms for visualizing the form and showing and uploading image(s) :
#model List<DataAccess.MCS_DocumentFields>
#{
ViewBag.Title = "Документ";
}
<div id="alabala">
<div id="drawForm">
#using (Html.BeginForm("UpdateDocument", "Forms", FormMethod.Post))
{
<table border="1" id="drawDocument">
<colgroup>
<col span="1" style="width: 10%;" />
<col span="1" style="width: 40%;" />
<col span="1" style="width: 25%;" />
<col span="1" style="width: 25%;" />
</colgroup>
#Html.Partial("_PartialHeader", Model)
#Html.Partial("_PartialDrawing", Model)
#Html.Partial("_PartialBody", Model)
#Html.Partial("_PartialFooter", Model)
</table>
if (ViewBag.Status == 1)
{
<button type="submit" id="submitDocument">Запази</button>
<button style="float:right;" id="finalizeDocument">Приключи</button>
}
else
{
#Html.ActionLink("Назад", "Index")
}
}
</div>
<div id="imageContainer">
<div id="imageGallery" style="overflow: scroll">
<img src="file:\\..." alt="docImg" style="width: 190px; height: auto"/>
#Ajax.ActionLink("Delete", "DeletePicture", new { documentID = Model[0].Id },
new AjaxOptions
{
Confirm = "Are you sure?",
OnComplete = "$('#blah').attr('src', '#').attr('style', 'display:none;'); $('#Image1').attr('src', '#').attr('style', 'display:none;'); $('#DelPic').attr('style', 'display:none;');"
})
<img src="file:\\..." alt="docImg" style="width: 190px; height: auto"/>
#Ajax.ActionLink("Delete", "DeletePicture", new { documentID = Model[0].Id },
new AjaxOptions
{
Confirm = "Are you sure?",
OnComplete = "$('#blah').attr('src', '#').attr('style', 'display:none;'); $('#Image1').attr('src', '#').attr('style', 'display:none;'); $('#DelPic').attr('style', 'display:none;');"
})
</div>
#using (Html.BeginForm("Upload", "Forms", FormMethod.Post))
{
<input name=#Model[0].DocumentId type="hidden" />
<input type="file" name="datafile" id="file" onchange="readURL(this);" />
<input type="button" name="Button" value="Upload" id="UploadButton" onclick="fileUpload(this.form,'/forms/upload','upload'); return false;"/>
<div id="upload" style="display: inline-block;">
<img id="blah" src="#" alt="your image" style="display:none;"/>
</div>
}
</div>
</div>
The first form is where I show the data for a current form/document and because they are editable I have submit button. I need the second form to submit the selected picture to my controller and there to perform the business logic.
So once a picture is selected and Upload button is clicked I get to my controller :
public ActionResult Upload(FormCollection collection)
{
WebImage UploadImage = WebImage.GetImageFromRequest();
long documentID;
string finalImageName = null;
if (!long.TryParse(collection.AllKeys[0], out documentID))
//More code...
Where I have the image and the id of the document that it belongs to and what I need is to perform some checks/validations and finally to coy the selected image to dedicated directory and save the name to the data base.
The problem is that I have all the logic written except the one that will show the correct messages for the different outputs like :
if (imagePath.Length > 247)
{
//TODO message that the path is too long
//TODO this return View() is temp, replace with something suitable
return View();
}
//...
System.IO.File.Copy(UploadImage.FileName, imagePath);
}
catch (Exception ex)
{
//TODO copy failed return message
return View();
}
//...
These are all different outputs from the execution of the same method and in the main view I want to show a proper message for each one of them. What I'm not sure is if I still have an option to save my work and still implement the message logic? Thinking now it seems that if I was using Ajax in some form it would be a lot easier now but I'm not. The only think I can think of know is creating ViewBag property, and returning it with the model to the view where to check the different properties and show some message if necessary based on that, but this means a lot of additional logic in my view, resending data from the database that I already have shown in my view and a lot of double work said in short, something that I consider as a bad programming, but maybe I got myself into this. So what is the best course of action from here on. Is it best to just remove my code and search for a way to do this with AJAX?
You can't upload a file using AJAX - you'd need some sort of 3rd party workaround. You need to return the original view from the Upload() method, with the appropriate model, and also a flag within the ViewBag somewhere to display the message, e.g.
public ActionResult Upload(UpdateDocumentModel model) {
...
if (imagePath.Length > 247) {
model.ErrorMessage = Errors.Over247;
return View("UpdateDocument", model);
}
...
return RedirectToAction("UploadOk");
}
I've changed your FormCollection to a strongly-typed model for ease of reading, plus that's what MVC.net is there for. The Errors.Over247 could be a string resource somewhere in your project, or a boolean flag which the View then reads to show a certain piece of HTML.
just use TempData instead of ViewBag
TempData["ErorrMessegge"] = "SomeMessage to view";
#TempData["ErorrMessegge"]
You can simply use TempData[] in order to pass parameter from Controller to View like below:
Controller:
[HttpPost]
public ActionResult Add(Applicant applicant)
{
repository.SaveApplicant(applicant);
TempData["message"] = "The applicant has been saved succesfully.";
return View(applicant);
}
View:
#if (TempData["message"] != null)
{
<div>#TempData["message"]</div>
}
The problem is I have two forms in the same view. The controller is Users and I have two actions for the two forms: Edit and UploadPhoto.
I have been using the Edit portion for awhile and it's working. Now I want to allow users to upload their photo on the same page. There is a separate button for saving the user information and another for saving the picture.
The page model is #model sportingbiz.Models.ViewModels.UserEditViewModel
The second form
<fieldset title="Upload photo">
<legend>Change Profile Picture</legend>
<div>
#using(Html.BeginForm("UploadPhoto", "Users", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table>
<tr>
<td>
<img src="#Url.Content("~/Content/images/noprofilepic.jpg")"
</td>
<td>
<input type="file" name="photoFile" />
<br /><br />
<input type="submit" value="Upload" />
</td>
</tr>
</table>
}
</div>
</fieldset>
Controller
public class UsersController : Controller
{
UsersRepository usersRepo = new UsersRepository();
[Authorize]
[HttpPost]
public void UploadPhoto(HttpPostedFile photoFile)
{
if (photoFile == null)
{
return;
}
if (photoFile.ContentLength <= 0)
{
return;
}
string filename = Path.GetFileName(photoFile.FileName);
if (Path.GetExtension(filename) == "")
return;
}
}
When I click upload my page navigates to http://localhost/mvcapp/Users/UploadPhoto with a blank screen. What I want is to return to the Edit page and probably show errors to the user that file was not uploaded. Features like ModelState.IsValid or ModelState.AddModelError
There is also no option of returning the same view e.g. return View(model)
Am I doing this wrong way? Some suggestion is to use Ajax uploader or Uploader. Am also thinking of separating the forms putting the Upload portion in its own view. Can PartialView help in this respect
[Authorize]
[HttpPost]
public void UploadPhoto(HttpPostedFile photoFile)
{
An Action with a void return is very strange. Make it return an ActionResult and determine on each branch where you want to go.
[Authorize]
[HttpPost]
public void UploadPhoto(HttpPostedFile photoFile)
{
if (photoFile == null)
{
return RedirectToAction("ErrorPage");
}
...
var viewModel = ...; // but your've lost the Edit part
return View(viewModel);
}
try to validate the using jquery like below, which will make sure that user are force to select some file...
lets us assume you a view like below
<input type="file" name="Document" id="imgFile" style="height:25px;"/>
<input type="submit" value="Submit" id="btnSubmit"/>
below is the jquery to validate
$('#imgFile').change(function() {
if ( ! $('#imgFile').val() ) {
alert('Chose a file!');
return false;
}
});
or you can do this same on the Button click like below
$('#btnSubmit').click(function() {
if ( ! $('#imgFile').val() ) {
alert('Chose a file!');
return false;
}
});
hope this might help you...
you uplode your image like that
public void UploadPhoto(HttpPostedFile photoFile)
{}
i think you should little bit change you code like this
public void UploadPhoto(HttpPostedFileBase photoFile)
{}