Let's assume I have a simple page with some information and a form.
#using (Html.BeginForm("UpdateOrder", "OrderController", FormMethod.Post)) {
// some inputs here
}
<p id="user_info">Some text here</p>
All input's data will be sent like model or by FormCollection to the Controller.
However, I want also to send to the controller any text\image, generally any information from the page that located outside the form. Here text with id "user_info" as an example.
I wonder if it could be implemented without jQuery, only by using default Controller's functionality.
You can do it simply
1- if you want to upload some documents or images than your form should be like
bellow code:
#using (Html.BeginForm("ApplyOnline", "Applieds", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<input type="hidden" name="JobId" id="JobId" value="#ViewBag.JobId" />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label class="control-label col-md-3">First Name (اسم)</label>
<div class="col-md-8">
#Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { #class = "form-control",#required="required" } })
#Html.ValidationMessageFor(model => model.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<input type='file' name='pmd' id='pmd' />
<input type="submit" value="Apply" class="btn btn-primary" />
}
than in countroller in post method
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ApplyOnline([Bind(Include = "Id,JobId,FirstName")] Applied applied, HttpPostedFileBase pmd, int JobId)
{
if (ModelState.IsValid)
{
//---save the data---------//
db.MyAppliedContext.Add(applied);
db.SaveChanges();
//---Get inserted Id----//
int insertedId = applied.Id;
//--------Upload PMD-------------------//
if (pmd != null && pmd.ContentLength > 0)
{
try
{
var PMDFileName = "PMD-" + applied.JobId + "-" + TrimedUser + "-" + insertedId + "-" + pmd.FileName;
//var P11FileName = DateTime.Now.ToString();
string path = Path.Combine(Server.MapPath("~/App_Data/system"),
Path.GetFileName(PMDFileName));
pmd.SaveAs(path);
UploadFiles MyPMDUploads = new UploadFiles();
MyPMDUploads.JobId = applied.JobId;
MyPMDUploads.ApplyId = insertedId;
MyPMDUploads.FileName = Path.GetFileName(PMDFileName);
MyPMDUploads.FilePath = path;
db.MyUploadFileContext.Add(MyPMDUploads);
db.SaveChanges();
ViewBag.Message = "PMD uploaded successfully";
}
catch (Exception ex)
{
ViewBag.Message = "ERROR PMD:" + ex.Message.ToString();
}
}
else
{
ViewBag.Message = "You have not specified a PMD file.";
}
}
return view(Model);
}
this way you can upload files and data all is included hop this help you
Try using hidden field to send additional data form to controller.
#using (Html.BeginForm("UpdateOrder", "Order", FormMethod.Post)) {
// some inputs here
<input type="hidden" name="user_info" id="user_info" value="Norway">
}
//<p id="user_info">Some text here</p>
and in OrderController controller action method
public ActionResult UpdateOrder(String user_info)
{
//Hidden filed **name** will be the name of the String
//From collection can be used in similar way
}
EDIT: you can update hidden field value by jQuery/javascript and after submission you can get updated value in controller and text/image it is slightly different
Related
I am having a hard time figuring out how to make Html.BeginForm to return the current Instance of Model instead of a new instance.
To explain what is wrong, when i write somthing in the TextBoxFor() and click on the submit button in the html.beginform(), it correctly does the AddStatus() and places it in the statusDict with the right key and is displayed on the right side in the view in the foreach loop. When i then click on the "fortsæt" button on the right side, it corrects loads the value into the TextBoxFor since i have it default to Model.MailTitel. Now i want to change what is in the Model.Mailtitel and when i click submit i want it to return this specific instance of the model to the controller but with a new value for MailTitel and since this would be a instance of the model already in the statusDict, it should just update the #status.Value.MailTitel. However since Html.BeginForm() returns a new instance of the model and thus is not in the statusDict which leads to it being added to it and thus shows as a new card on the right side.
So my question is: How to make Html.BeginForm() return the same instance of Model as the controller gave to the view?
Code:
View:
#using DS_Prototype.Models
<!--Left side - Info filling -->
<div class="split left">
#using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
#Html.AntiForgeryToken() // helps mitigate against cross-site request forgery
#Html.TextBoxFor(Model => Model.MailTitel, new { #Value = Model.MailTitel })
<button type="submit" class="btn btn-block btn-login">Submit</button>
}
</div>
<!--Right side - Status overview -->
<div class="split right">
#foreach (KeyValuePair<string, DriftStatus> status in (Dictionary<string, DriftStatus>)Session["statusDict"])
{
<div class="card">
<div class="card-body">
#status.Value.MailTitel
<div class="btn-group btn-group-justified">
#Html.ActionLink("Fortsæt", "ContinueStatus", "Home", new { status_id = status.Key }, new { #class = "btn btn-primary" })
#Html.ActionLink("Afslut", "EndStatus", "Home", new { #class = "btn btn-primary" })
</div>
</div>
</div>
}
</div>
Controller:
public ActionResult Submit(DriftStatus driftstatus) {
AddStatus(driftstatus);
ModelState.Clear();
return View("Index", new DriftStatus());
}
public ActionResult ContinueStatus(string status_id)
{
return View("Index",FindStatus(status_id));
}
private DriftStatus FindStatus(string key)
{
Dictionary<string, DriftStatus> statusDict = Check_statusDict();
DriftStatus driftstatus = statusDict[key];
if (driftstatus == null)
{
return new DriftStatus();
}
return statusDict[key];
}
private void AddStatus(DriftStatus driftstatus)
{
Dictionary<string, DriftStatus> statusDict = Check_statusDict();
if (!statusDict.ContainsKey(driftstatus.Created))
{
driftstatus.Created = DateTime.Now.ToString();
statusDict.Add(driftstatus.Created, driftstatus);
}
}
I have a MVC 5 controller with views, using Entity Framework project.
I have a controller and view for my Item Model:
public partial class Item
{
public int ItemID { get; set; }
public string ImageURL { get; set; }
}
I changed the Entity Framework Create view and controller to post an html file input and save the file path as the ImageURL
A snippet from the view looks like this:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
<fieldset>
<legend>Upload a file</legend>
<div class="editor-field">
#Html.TextBox("file", "", new { type = "file" })
</div>
</fieldset>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
The controller's Create ActionResult looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ItemID,ImageURL")] Item item, HttpPostedFileBase file)
{
try
{
if (ModelState.IsValid && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Uploads"), fileName);
file.SaveAs(path);
item.ImageURL = "/Uploads/" + file.FileName;
db.Items.Add(item);
db.SaveChanges();
}
ViewBag.Message = "Upload successful";
return RedirectToAction("Index");
}
catch
{
ViewBag.Message = "Upload failed";
ViewBag.ItemTypeID = new SelectList(db.ItemTypes, "ItemTypeID", "ItemType1", item.ItemTypeID);
return View(item);
}
}
As you can see I use var fileName = Path.GetFileName(file.FileName); and item.ImageURL = "/Uploads/" + file.FileName; To populate my ImageUrl. The file itself is saved on the server.
Now my issue is that I don't know how to get the "Edit" view and ActionResult to allow me either to keep the same image or upload a new image.
How can I do this?
What I have done so far is in the Edit view to write:
<div class="form-group">
#if (Model.ImageURL == null)
{
<fieldset>
<legend>Upload a file</legend>
<div class="editor-field">
#Html.TextBox("file", "", new { type = "file" })
</div>
</fieldset>
}
else
{
/*Keep or upload new image here*/
}
</div>
What would I need to write in that else {...} and what would I need to write in the controller's public ActionResult Edit(int? id) {...} ?
Just show Image in the img control and below that use another file control , in case user need to change the uploaded image..
<div class="form-group">
#if (Model.ImageURL == null)
{
<fieldset>
<legend>Upload a file</legend>
<div class="editor-field">
#Html.TextBox("file", "", new { type = "file" })
</div>
</fieldset>
}
else
{
/*show Image in an img control using image path*/
<img src="#Model.ImageURL" height="100" width="100" />
<fieldset>
<legend>change the file</legend>
<div class="editor-field">
#Html.TextBox("file", "", new { type = "file" })
</div>
</fieldset>
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
and at Action part everything will be same , remove the old file and save new one and update db as well.
also Don't forget to use form as you have used in the create view.
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
if image is not uploaded For the particular item How you will edit . You can do create and edit both in single action method by
var itemInDb = db.items
.Where(c => c.itemid== id) // or whatever your key is
.SingleOrDefault();
if (itemInDb != null)
db.Countries.ApplyCurrentValues(item);
else
db.Countries.AddObject(item);
db.SaveChanges();
if multiple images are there for single image you can loop it
I have this kind of problem: In a view I have one button upload which uploads an image and stores it to some folder. Is there a way to call action upload, but not to return a view? Just to save that content, and then I have another button next which will redirect me to a new view. I tried with return type void, but it sends me to blank page.
This are form buttons for upload and next
#using (Html.BeginForm("Upload", "Account", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.LabelFor(model => model.Picture, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<span class="btn btn-primary btn-file">
Choose <input type="file" name="file" />
</span>
<input type="submit" value="Upload" name="buttonName" class="btn btn-primary"/>
</div>
</div>
}
#using (Html.BeginForm("Next", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
<div class="col-md-10">
<input type="submit" value="Next" name="buttonName" class="btn btn-default" />
</div>
</div>
}
This is action:
public void Upload(HttpPostedFileBase file, string btnSubmit)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
file.SaveAs(path);
}
}
You can use the Content() method to return ContentResult ContentResult by default returns a text/plain as its contentType.
public ActionResult Upload(HttpPostedFileBase file, string btnSubmit)
{
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
file.SaveAs(path);
}
return Content("Success");
}
You could return an EmptyResult.
MVC wants you to use EmptyResult when the action is specifically
intended to return nothing. Unlike all of the previous ActionResults
though, EmptyResult doesn't have a helper. Additionally, if an action
returns null, MVC will detect that and make it return an EmptyResult.
Ok, I searched about this and I think that i need some ajax without refreshing page. I found this File upload using MVC 4 with Ajax. I'll try it to see if this works.
The correct solutions are to use either:
return new HttpStatusCodeResult(HttpStatusCode.OK);
to indicate the upload was received and all processing has completed.
return new HttpStatusCodeResult(HttpStatusCode.Accepted);
to indicate the upload was received and further processing will continue.
I am dynamically populating form(s) in my view (MVC) and I can have one or many forms on the same page. Each form is uniquely named, however the field variables in each form remain the same.
It works a treat with each form having its own submit button and passing the input to my Post Controller method, but now I need to add the option to submit all or one form by clicking the "next page" link. As I already have JQuery loading, I am trying to do this with Ajax and Json but I am stuck.
View
#using Microsoft.AspNet.Identity
#model IEnumerable<Template.Models.GetViewModel>
#{
ViewBag.Title = "About me";
ViewBag.Page = Model.First().PageNumber;
}
#Html.AntiForgeryToken();
#foreach (var q in Model.OrderBy(o => o.QuestionRanking))
{
var qtype = q.QuestionTypeId;
Html.BeginForm("ViewQuestion", "Question", FormMethod.Post, new { #class = #q.ShowHide + " form-horizontal", id = #q.FormNumber, role = "form" });
<div>
<h1>#q.QuestionRanking. #q.Question1</h1>
</div>
<div class="form-group">
#Html.TextArea("Answer", q.Answer, new { #class = "form-control", rows = "4", cols = "10" })
</div>
<div class="form-group">
<input type="submit" name="#q.FormNumber" class="btn btn-primary" value="Save answer" />
</div>
<hr />
Html.EndForm();
}
<p>
#Html.ActionLink("Previous", "ViewQuestion", new { page = ViewBag.Page - 1 }) |
#Html.ActionLink("Next", "ViewQuestion", new { page = ViewBag.Page + 1 })
</p>
#section Scripts {
#Scripts.Render("~/bundles/jquery")
}
The controller
[HttpPost]
public ActionResult ViewQuestion([Bind(Include = "QuestionId, UserId")] ResponseViewModel responseViewModel)
{
var page = System.Web.HttpContext.Current.Request["page"];
var newAnswer = System.Web.HttpContext.Current.Request["Answer"];
var re = new Response
{
Answer = newAnswer,
UserId = responseViewModel.UserId,
QuestionId = responseViewModel.QuestionId,
};
_db.Responses.Add(re);
_db.SaveChanges();
}
I haven't gotten very far with my script and I am lost as to how to get the values to my controller;
<script>
function postValues() {
var str = $( "form" ).serialize();
$( "#results" ).text( str );
}
</script>
Any advice or examples would be greatly appreciated.
To use ajax you can convert your forms using the following
#using(Ajax.BeginForm("ViewQuestion","Question",null,new AjaxOptions{ options here },
new { #class = #q.ShowHide + " form-horizontal", id = #q.FormNumber, role = "form"
}))
{
#Html.AntiForgeryToken();
<div>
<h1>#q.QuestionRanking. #q.Question1</h1>
</div>
<div class="form-group">
#Html.TextArea("Answer", q.Answer, new { #class = "form-control", rows = "4",
cols = "10" })
</div>
<div class="form-group">
<input type="submit" name="#q.FormNumber" class="btn btn-primary"
value="Save answer" />
</div>
<hr />
}
then you can use jquery to submit each form
$('form').each(function(){
$(this).submit();
});
with regards to #Html.AntiForgeryToken(); this should be within each form, and if you want to use it you need to add [ValidateAntiForgeryToken] to your controller action
i'm trying to upload a file with ASP MVC4, i give you my situation:
I have a model class "Movie" with some atributes (doesn't matter)
I want to add some code to my controller and View part without touching the model, because we want to make the image difrent to the model.
So, here's an example of my view code, i'll bold the lines added by me:
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Movie</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Duration)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Duration)
#Html.ValidationMessageFor(model => model.Duration)
</div>
//ADDED BY ME:
<div class="editor-label">
<p>Select a file</p>
</div>
<div class="editor-field">
<input type="file" name="fileUpload" />
</div>//END OF MY CODE
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
So you can see that i have some code generated by ASP which allows me to add a new user to the db, and a "input" added by me to upload the image.
The problem is that when i try to recover that image from the controller, the "Request.Files" atributte is empty, so i can't recover any image, and of course i can't upload it, here's my controller code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Movie movie)
{
if (ModelState.IsValid)
{
db.MovieContext.Add(movie);
db.SaveChanges();
foreach (string file in Request.Files)
{
var postedFile = Request.Files[file];
postedFile.SaveAs(Server.MapPath("~/UploadedFiles") + pelicula.Id);
}
return RedirectToAction("Index");
}
return View(movie);
}
Don't know why the "Request.Files" is empty, so if anyone can help me it would be great, Thank you so much
Try the below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Movie movie, HttpPostedFile fileUpload)
{
if (ModelState.IsValid)
{
db.MovieContext.Add(movie);
db.SaveChanges();
var postedFile = fileUpload;
postedFile.SaveAs(Server.MapPath("~/UploadedFiles") + pelicula.Id);
return RedirectToAction("Index");
}
return View(movie);
}
Lets see if we can find out whats wrong. Try the following and show us the errors:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Movie movie, HttpPostedFile fileUpload)
{
if (ModelState.IsValid)
{
db.MovieContext.Add(movie);
db.SaveChanges();
var postedFile = fileUpload;
postedFile.SaveAs(Server.MapPath("~/UploadedFiles") + pelicula.Id);
return RedirectToAction("Index");
}
var content = "";
foreach (ModelState modelState in ViewData.ModelState.Values)
{
foreach (ModelError error in modelState.Errors)
{
content += error.ErrorMessage + ", " + error.Exception + "<br/>";
}
}
return Content(content);
//return View(movie);
}
Antevirus has the answer but I hat to dig into comments to find it out. In short the problem for was that I didnt specify any encodings for my form which is
enctype = "multipart/form-data"
Here is the full code:
#using (Html.BeginForm("Create", "Members", FormMethod.Post, new { #id = "member-form", #enctype = "multipart/form-data" }))
{
<div class="form-group">
<label class="control-label col-md-2">Picture</label>
<div class="col-md-10">
<input id="fileUpload" type="file" name="fileUpload" class="file-loading">
</div>
</div>
}
I am using file-input for bootstrap