Just started with MVC and trying to do the following:
having a Details.cshtml with the following part on one of my tabs:
<!-- DETAILS TAB CONTENT -->
<div class="tab-pane profile active" id="details-tab">
#if (ViewBag.ScreenMode == Constants.ScreenMode.View)
{
#Html.Partial("_ViewDetails", Model)
}
else
{
#*#Html.Partial("_EditDetails", Model)*#
<div id="DetailsEdit">
#{Html.RenderPartial("_EditDetails");}
</div>
}
</div>
My _ViewDetails.cshtml shows detail information and has the following to go to the Edit mode:
#Html.ActionLink("Edit", "Details", new { id = Model.EmployeeId, screenMode = Constants.ScreenMode.Edit })
When clicked, indeed the tab shows the contents of the partial view _EditDetails. My _EditDetails.cshtml looks like this:
#using (Html.BeginForm("Edit", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.EmployeeId)
#* fields with editable controls. Left it out here *#
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
and having the following methods in my controller:
public ActionResult Details(Guid? id, Constants.ScreenMode? screenMode)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Employee employee = employeeManager.Get(id.GetValueOrDefault());
if (employee == null || employee.EmployeeId == null || employee.EmployeeId == Guid.Empty)
return HttpNotFound();
if (screenMode == null)
screenMode = Constants.ScreenMode.View;
ViewBag.ScreenMode = screenMode;
return View(employee);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Guid? id, HttpPostedFileBase upload)
{
// code here
return RedirectToAction("Details", "Employee", new { id = employeeToUpdate.EmployeeId, screenMode = Constants.ScreenMode.View });
}
However, when I press the save button from the edit partial view, it never hits my code Edit action in my controller. It only goes back to the Details action, which gets the info again. I thought by using the following at the beginning of my partial view, I could make the post go to my Edit action:
#using (Html.BeginForm("Edit", "Employee", FormMethod.Post, new { enctype = "multipart/form-data" }))
What do I miss or are my thoughts completely wrong?
Thanks in advance.
Aarghhhh, found it.
My Details.cshtml started with:
#using (Html.BeginForm("Details", "Employee", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Removed this and now it's working.
Overlooked this for days.
Thanks.
Related
Trying to print the selected file type as an header 3 to make sure it is passing into the next model. I was hoping it wold be activated after the submit button in the view but nothing comes up. I've got it working with a text box but cant seem to understand how to access it with a drop down list.
I am using Httpget and httppost and it doesn't seem to work.
Model
namespace FindFileStringFinal.Models
{
public class FileTypeModel
{
public string SelectedType { get; set; }
public IEnumerable<SelectListItem> Type { get; set; }
}
}
Controller
[HttpGet]
public ActionResult Index()
{
var fileType = new FileTypeModel();
fileType.Type = new[]
{
new SelectListItem { Value = "1", Text = "Xml", Selected=true },
new SelectListItem { Value = "2", Text = "Html" },
new SelectListItem { Value = "3", Text = "Css" },
new SelectListItem { Value = "4", Text = "C#" }
};
return View(fileType);
}
[HttpPost]
public ActionResult Index(FileTypeModel fileType)
{
var dir = new DirectoryModel();
**dir.Type = fileType.SelectedType;**
return View();
}
View
#model FindFileStringFinal.Models.FileTypeModel
#{
ViewBag.Title = "Index";
}
<h3>File Type</h3>
#using (Html.BeginForm("Index", "Find", FormMethod.Get))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Type, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.SelectedType,new SelectList(Model.Type, "Value", "Text"),
"Select a File Type", new { #class = "form-control" })
</div>
</div>
#using (Html.BeginForm("Index", "Find", FormMethod.Post))
{
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<h3>Selected: #Model.SelectedType</h3>
<input type="submit" value="Find" class="btn btn-default" />
</div>
</div>
}
</div>
}
<div>
#Html.ActionLink("Find Directory", "About")
</div>
I have this exact same code for two textboxs with the same input button and it prints out as a header 3 so it shows me that the information is being stored.
Why is it not working this the dropboxlist? I also put httppost inside of get because I only need to receive the information in that part and nothing else.
I don't know if that is good or bad practice because I could barely find httpget and httppost tutorials that focus primarily on how it works or doesn't work inside the view.
Any feedback would be helpful since this is my first time working with MVC.
I'm trying to create a page that whilst editing an "Asset" the user can upload a picture within a partial view.
On submitting the picture I would like the filename to be saved to server location and prefixed with its Asset ID number for obvious reasons and then return the partial view but with the picture in.
So when the user submits the edit page the changed details as well as a new shiny picture url is saved to the DB.
Heres what I have so far.
Edit View (Edit.cshtml)
#model Asset_Manager.DB.Asset
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Asset</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.Aid)
**** other fields
<div class="form-group">
#Html.LabelFor(model => model.Picture_Location, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Partial("~/Views/Asset/UploadAssetImage.cshtml",Model)
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Partial Upload View (UploadAssetImage.cshtml)
#model Asset_Manager.DB.Asset
#using (Html.BeginForm("UploadPicture", "Asset", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<img src="#Model.Picture_Location" alt="#Model.Description" width="250" height="250" /><br />
<input type="file" name="file" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
<input type="hidden" name="id" value="#Model.Aid" />
}
and finally Controller Method (AssetController.cs)
[HttpPost]
public ActionResult UploadPicture(int id,FormCollection collection)
{
if (Request.Files.Count > 0)
{
var file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = "Asset_" + id + "_" + Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Content/AssetImages/"), fileName);
file.SaveAs(path);
}
}
Asset A = new Asset();
A = _dal.GetAssetByID(id);
return PartialView("UploadAssetImage", A.Aid);
}
Now My Issues
Each time I try to submit a photo I get kicked right out to the Asset index (Index.cshtml) page let alone be able to see if sending the entire edit works.
Also the breakpoint under the controller method doesn't trigger so I cant trace where the issue could be.
Any Help / Examples / Pointers in the right direction would be appreciated.
You have a form within a form, which is invalid HTML. The outermost form is what is being submitted, and this form, importantly, does not include the enctype="multipart/form-data" attribute. Add that attribute to your form in the view and remove the form in your partial.
I'm creating ASP.NET web application using MVC and Entity Framework. I have two different success messages I am passing to an index action for when a user clocks in or clocks out. The success message will print correctly when a user clocks in, but will not when a user clocks out for some reason.
The actions are very similar and I used all of the same conventions so I can't figure out why one would print and another would not. I've tried debugging and there are no red flags and everything updates in the database like it should. Is it not possible to pass multiple TempData variables to the same action?
Here is the relevant code:
Controller
// GET: TimeClocks
public ActionResult Index()
{
ViewBag.ClockInSuccess = TempData["ClockInSuccess"];
ViewBag.ClockOutSuccess = TempData["ClockOutSuccess"];
return View();
}
[HttpPost]
public ActionResult ClockIn(TimeClock timeClock)
{
if(db.TimeClocks.ToList().Count == 1)
{
ModelState.AddModelError("ExistsError", "You already clocked in at" + timeClock.ClockIn);
}
string currentUserId = User.Identity.GetUserId();
ApplicationUser currentUser = db.Users.FirstOrDefault(x => x.Id == currentUserId);
timeClock.ApplicationUser = currentUser;
timeClock.ClockIn = DateTime.Now;
if (ModelState.IsValid)
{
db.TimeClocks.RemoveRange(db.TimeClocks.ToList());
db.TimeClocks.Add(timeClock);
db.SaveChanges();
TempData["ClockInSuccess"] = "You clocked in successfully at " + timeClock.ClockIn;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}
[HttpPost]
public ActionResult ClockOut(TimeClock timeClock)
{
timeClock = db.TimeClocks.FirstOrDefault();
if(timeClock.ClockIn == null)
{
ModelState.AddModelError("NullError", "You must clock in before you can clock out.");
return RedirectToAction("Index");
}
timeClock.ClockOut = DateTime.Now;
if (ModelState.IsValid)
{
db.Entry(timeClock).State = EntityState.Modified;
db.SaveChanges();
TempData["ClockOutSuccess"] = "You clocked out successfully at " + timeClock.ClockOut;
return RedirectToAction("Index");
}
return RedirectToAction("Index", timeClock);
}``
View
#model FinalProject.Models.TimeClock
#{
ViewBag.Title = "Create";
}
<h2>Employee Time Clock</h2>
#using (Html.BeginForm("ClockIn", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock In" class="btn btn-lg" />
</div>
</div>
</div>
}
#using (Html.BeginForm("ClockOut", "TimeClocks"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Clock Out" class="btn btn-lg" />
</div>
</div>
</div>
}
#{
if (#ViewBag.ClockInSuccess != "")
{
<p class="alert-success">#ViewBag.ClockInSuccess</p>
}
else if (#ViewBag.ClockOutSuccess != "")
{
<p class="alert-success">#ViewBag.ClockOutSuccess</p>
}
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
TempData is lost once you read it so you need to do a Peek or a Keep:
ViewBag.ClockInSuccess = TempData.Peek("ClockInSuccess");
ViewBag.ClockOutSuccess = TempData.Peek("ClockOutSuccess");
http://www.codeproject.com/Articles/818493/MVC-Tempdata-Peek-and-Keep-confusion
I have the following code in controller
[HttpPost]
public ActionResult Create(AdminDetailsViewModel viewmodel)
{
if (ModelState.IsValid)
{
viewmodel.CreatedDate = DateTime.Now;
HttpPostedFileBase file = Request.Files["ImageData"];
if (file.FileName=="")
{
// file object take image from this path ("~/images/computer.png");
}
ImageRepository IR = new ImageRepository();
int i = IR.UploadImageInDatabase(file, viewmodel);
if (i == 1)
{
return RedirectToAction("Index");
}
}
return View(viewmodel);
}
Following is the view
<div class="form-group">
#Html.LabelFor(model => model.AdminImage, new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" name="ImageData" id="ImageData" onchange="fileCheck(this);" />
</div>
</div>
UploadImageInDatabase() function saves the image into the database
what should I write inside the if condition of Create function so that HttpPostedFileBase file object will take the file from ("~/images/computer.png"); this path if it is null
Please use like below in your form on view
#using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post, new { enctype = "multipart/form-data", #class = "form-horizontal" }))
Note : You need to mention the enctype = "multipart/form-data" in your form this will helps you to get the solution.
I want to set a bool to true in the controller when producing a certain view and then alter the header of the view accordingly. This should be dead simple but instead Im getting:
Cannot perform runtime binding on a null reference Exception Details:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot perform
runtime binding on a null reference
All I'm doing is in controller:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = true;
return View();
}
and then in view:
#if (ViewBag.IsRegistration)
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
but it fails on:
#if (ViewBag.IsRegistration)
UPDATE
Relevant Controller Code:
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.IsRegistration = "true";
return View();
}
The register view:
#model Mvc.Models.RegisterViewModel
#{
Layout = "~/Views/Shared/_AccountLayout.cshtml";
ViewBag.Title = "Register";
}
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
<div class="row">
<div class="col-lg-6">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset class="form-horizontal">
<legend>Create a new account.</legend>
<div class="control-group">
#Html.LabelFor(m => m.UserName, new { #class = "control-label" })
<div class="controls">
#Html.TextBoxFor(m => m.UserName)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.Password, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.Password)
</div>
</div>
<div class="control-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "control-label" })
<div class="controls">
#Html.PasswordFor(m => m.ConfirmPassword)
</div>
</div>
<div class="form-actions no-color">
<input type="submit" value="Register" class="btn" />
</div>
</fieldset>
}
</div>
<div class="col-lg-6"></div>
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new { ReturnUrl = ViewBag.ReturnUrl })
</section>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
The ExternalLoginsList partial:
#using Glimpse.Core.Extensions
#using Microsoft.Owin.Security
#model ICollection<AuthenticationDescription>
#if (Model.Count == 0)
{
<div class="message-info">
<p>There are no external authentication services configured</p>
</div>
}
else
{
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
<fieldset id="socialLoginList">
#if (!string.IsNullOrEmpty(ViewBag.IsRegistration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
<p>
#foreach (AuthenticationDescription p in Model) {
<button type="submit" class="btn" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
}
</p>
</fieldset>
}
}
Try:
#if (ViewBag.IsRegistration == true)
I know this is an old question, but I think I have an elegant answer, so in case anyone reads this after searching, here is mine:
#if (ViewBag.IsRegistration ?? false)
Try this:
Replace the line in your controller:
ViewBag.IsRegistration = true;
with
ViewBag.IsRegistration = new bool?(true);
and replace the line in your view:
#if (ViewBag.IsRegistration)
with
#if ((ViewBag.IsRegistration as bool?).Value)
Effectively you are putting a nullable bool in the ViewBag and then unwrapping it.
Simply check for null before checking for true:
if (ViewBag.IsRegistration != null && ViewBag.IsRegistration)
Try TempData instead of ViewBag.
Change your code from
Controller
ViewBag.IsRegistration=true;
to
TempData["IsReg"]=true;
and in View
#if((bool)TempData["IsReg"])
It seems that you are using the value in child partial view and you are adding the data in parent action.The values in viewbag cannot pass out data from one action to anothers action's view. While TempData use session it can be used to pass data to one action to another actions view.
Ok so as per Floods suggestion in comments, I need to pass the arguments around. The ViewBag from the parent View does not flow through to partial views.
So in the code for the Register View I needed to change from
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList", new {ReturnUrl = ViewBag.ReturnUrl})
</section>
to
<section id="socialLoginForm">
#Html.Action("ExternalLoginsList",
new {ReturnUrl = ViewBag.ReturnUrl,
IsRegistering = #ViewBag.IsRegistering })
</section>
Then go into my account controller and change from:
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
to
[AllowAnonymous]
[ChildActionOnly]
public ActionResult ExternalLoginsList(string returnUrl, string isRegistering) {
ViewBag.IsRegistering = (isRegistering.ToLower() == "true");
ViewBag.ReturnUrl = returnUrl;
return (ActionResult)PartialView("_ExternalLoginsListPartial", new List<AuthenticationDescription>(AuthenticationManager.GetExternalAuthenticationTypes()));
}
Then in the ExternalLogins I can just:
#if (ViewBag.IsRegistering)
as necessary.
So Im effectively passing the IsRegistering bool from controller to main view then back up to action method on controller then into ViewBag which allow me to access the bool in the child partial view.
Many thanks.
Booleans in Viewbag are always tricky. Try this instead
[AllowAnonymous]
public ActionResult Register()
{
ViewBag.Registration = "x";//x or whatever
return View();
}
#if (!String.IsNullorEmpty(ViewBag.Registration))
{
<legend>Register using another service.</legend>
}
else
{
<legend>Use another service to log in.</legend>
}
Maybe so:
#if ((ViewBag.IsRegistration != null) && (ViewBag.IsRegistration is bool) && (bool)ViewBag.IsRegistration)
{
}