Approve and Reject in ASP.NET MVC3 - asp.net-mvc-3

I know this question is not that hard but I'm new to asp.net mvc3 and I don't have an idea how to do this. I created a simple CRUD function in my controller. Now in my edit I changed the textbox to a two radio button Approve and Reject. Now my question is how could I let my edit get the value of the radio button that I choose? Here are the value of my radio buttons in my View>Edit
My VIEW>EDIT
<div class="editor-label">
#Html.LabelFor(model => model.Status)
</div>
<div class="editor-field">
<input type="radio" name="action" value="Approve" />Approve
<input type="radio" name="action" value="Reject"/>Reject
</div>
Here is the Edit in my Controller I don't know what to modify here.. :(
public ActionResult Edit(int id)
{
Leave leave = db.Leaves.Single(l => l.leave_id == id);
return View(leave);
}
[HttpPost]
public ActionResult Edit(Leave leave)
{
if (ModelState.IsValid)
{
db.Leaves.Attach(leave);
db.ObjectStateManager.ChangeObjectState(leave, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(leave);
}
Here is the model of my leave

Try to use Html.RadioButtonFor() helper:
#Html.RadioButtonFor(model => model.Status, "Approve") Approve
#Html.RadioButtonFor(model => model.Status, "Reject") Reject
instead of
<input type="radio" name="action" value="Approve" />Approve
<input type="radio" name="action" value="Reject"/>Reject
It depends from the type of your Status.
If it's bool than DevDave's example should work fine.
If it's string - than my first example should be ok.
But if it's int with values 0 for Reject and 1 for Approve - you should use something like this:
#Html.RadioButtonFor(model => model.Status, "1") Approve
#Html.RadioButtonFor(model => model.Status, "0") Reject

Assuming you use a bool value for Status:
<label for="approve">
#Html.RadioButtonFor(x => x.Status, "True", new { id = "approve" })
Approve
</label>
<label for="reject">
#Html.RadioButtonFor(x => x.Status, "False", new { id = "reject" })
Reject
</label>
Edit: It is bad practice to expose your db object, you should use a view model that has the relevant properties from your db object and then you can map between the two when saving/loading.
I.e. return LeavesViewModel to view, but convert your LeavesViewModel into db oject on save.
In the example provided, this should directly map to the Leave object that is passed into your Post method, assuming it is a bool value. Debug and you should see the value come back true or false depending on the option you choose.
It may also work if Status is an Enum with more than two (i.e. bool) options but I have not tried that before.
So in your edit view, wrap your radio buttons and other parts of the form in:
#using (Html.BeginForm("Edit", "ControllerName")) {
..your stuff
<input type="submit" value="Save" />
}

Related

Passing Viewbag Data from View to Controller in ASP.Net MVC3 Razor

In my ASP.Net MVC3 Razor project i have to pass value from view to controller.The view contains one submit button that is used to pass selected image file and two other input data.This two input data is from a controller named "FileUpload"(ViewBag.Data1 = CusId;ViewBag.Data2 = Name;).When submitting the button i have to pass these three (Image,CusId,Name) to another controller to upload the image file.
Controller Code
public ActionResult FileUpload(int CusId, string Name)
{
ViewBag.Data1 = CusId;
ViewBag.Data2 = Name;
return View();
}
[HttpPost]
public ActionResult UploadPhoto(ElixiCustPro elixi, HttpPostedFileBase file)
{
//return null;
try
{
if (file != null && file.ContentLength > 0)
{
if ((file.ContentType == "image/jpeg") || (file.ContentType == "image/gif") || (file.ContentType == "image/png"))//check allow jpg, gif, png
{
elixi.Image = new byte[file.ContentLength];
file.InputStream.Read(elixi.Image, 0, file.ContentLength);
var filename = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/ElixirFiles/UploadImagesElixir/"), filename);
file.SaveAs(path);
ecp.Image = new byte[file.ContentLength];
ecp.ImageUrl = path;
ment.ElixiProData.Add(ecp);
ment.SaveChanges();
return RedirectToAction("ImageResult");
}
}
}
catch (Exception ex)
{
return View(ex.Message.ToString());
}
return View();
}
View Code
#using (Html.BeginForm("UploadPhoto", "Home", FormMethod.Post, new { #enctype = "multipart/form-data" }))
{
#* <div class="form-group">
<label class="col-lg-2 control-label">
Customer ID</label>
<div class="col-lg-10">#Html.TextBoxFor(model => model.CusId, new { #class = "form-control" })</div>
<label class="col-lg-2 control-label">
Customer Name</label>
<div class="col-lg-10">#Html.TextBoxFor(model => model.Name, new { #class = "form-control" })</div>
</div>*#
<input type="hidden" id="id" />
<div class="col-md-6">
<div class="form-group">
<label class="col-lg-2 control-label">
DMIT Image</label>
<div class="col-lg-10">
#ViewBag.Data1
#ViewBag.Data2
<input type="file" id="file" name="file">
<input type="submit" class="btn btn-success" value="Upload" />
</div>
</div>
</div>
}
ViewBag can't pass data back to controller. You should post those values back inside the form. Easiest thing would be to not to use ViewBag and add the data to model type.
Then you can pass them with hidden inputs using HTML helpers like this:
#Html.HiddenFor(item => item.CustomerId)
#Html.HiddenFor(item => item.ImageId)
If that's not possible, you can add the hidden inputs manually. Just keep in mind that the name attributes are important for model binding.
<input type="hidden" name="CustomerId" value="#ViewBag.Data1" />
Yes you cannot pass a Viewbag from view to controller.
But you can pass them using TempData.
Add this to your View.
#{TempData["Data1"]=ViewBag.Data1}
#{TempData["Data2"]=ViewBag.Data2}
But this TempData passes the information as an object.
So typecasting is necessary in your Controller.
int x=Convert.ToInt32(TempData["Data1"]);
string y=(TempData["Data2"]).ToString();
I tried,it is working.
or you can send TempData from Controller in get method,and use the same to pass from view to post method instead of Viewbag.

Using Html.RadioButtonFor with a boolean isn't writing Checked="Checked"

I am having an issue using the RadioButtonFor helper. When the value passed in is true, it isn't displaying a "check" in either radio button. When the value is false, it works just fine.
I copied this code from the project I am working on and created a sample application and I was able to replicate the issue. If I hard coded the value to true or false it seems to work, but when I use the "!string.IsNullOrEmpty(allgroups)" it doesn't.
From the View:
<div>
#Html.RadioButtonFor(m => m.AllGroups, true) All Groups
#Html.RadioButtonFor(m => m.AllGroups, false) Current Groups
</div>
From the ViewModel:
public bool AllGroups { get; set; }
From the Controller:
public ActionResult Index(string allgroups)
{
var model = new ProgramGroupIndexViewModel
{
AllGroups = !string.IsNullOrEmpty(allgroups)
};
return View(model);
}
From view source in IE:
<div>
<input id="AllGroups" name="AllGroups" type="radio" value="True" /> All Groups
<input id="AllGroups" name="AllGroups" type="radio" value="False" /> Current Groups
</div>
From view source when value of AllGroups is false (note it works):
<div>
<input id="AllGroups" name="AllGroups" type="radio" value="True" /> All Groups
<input checked="checked" id="AllGroups" name="AllGroups" type="radio" value="False" /> Current Groups
</div>
The model binding is getting confused because you named your action parameter the same as your model property. Change the name of your Index action parameter, and it should work.
public ActionResult Index(string showAllGroups)
{
var model = new ProgramGroup
{
AllGroups = !string.IsNullOrEmpty(showAllGroups);
};
return View(model);
}
if you are returning bool from model then there is no need to check uncheck explicitly mvc will do it itself just write
<div>
#Html.RadioButtonFor(m => m.AllGroups)
#Html.RadioButtonFor(m => m.AllGroups)
</div>
however if you want to do it explicitly then
you should use following syntax to check / uncheck
Html.RadioButtonFor(m => m.AllGroups, "DisplayText", new { #checked = "checked" })
In source code you can see that it is setting true / false for value not checked attribute
in your view you can write
#if(m.AllGroups)
{
Html.RadioButtonFor(m => m.AllGroups, "DisplayText", new { #checked = "checked" })
}
else
{
Html.RadioButtonFor(m => m.AllGroups, "DisplayText" })
}

MVC3: Portions of Model Not Reconstituted on Postback

Portions of my models are not being correctly reconstructed on postback.
Models
public class DemographicsModel
{
public List<QuestionModel> Questions { get; set; }
}
public abstract class QuestionModel
{
[HiddenInput(DisplayValue = false)]
public int ID { get; set; }
[HiddenInput(DisplayValue = false)]
public string Title { get; set; }
}
public abstract class ChooseQuestionModel : QuestionModel
{
public abstract List<SelectListItem> Items { get; set; }
}
public class ChooseManyQuestionModel : ChooseQuestionModel
{
[Required]
[DataType("CheckBoxList")]
public override List<SelectListItem> Items { get; set; }
}
Views
ChooseManyQuestionModel.cshtml
#model X.Y.Z.ChooseManyQuestionModel
<div class="Form Wide NoLabel">
<div class="Title">#this.Model.Title</div>
#Html.TypeStamp()
#Html.EditorFor(m => m.ID)
#Html.EditorFor(m => m.Title)
#Html.EditorFor(m => m.Items)
</div>
CheckBoxList.cshtml
#model IEnumerable<SelectListItem>
#if (!this.Model.IsNullOrEmpty())
{
foreach (var item in this.Model)
{
<div>
#Html.HiddenFor(m => item.Value)
#Html.HiddenFor(m => item.Text)
#Html.CheckBoxFor(m => item.Selected)
#Html.LabelFor(m => item.Selected, item.Text)
</div>
}
}
I believe the issue lies within CheckBoxList.cshtml since these items are not being re-constituted on postback.
HTML Output
<div class="Form Wide NoLabel">
<div class="Title">Question title displays here?</div>
<input id="Questions_1___xTypeStampx_" name="Questions[1]._xTypeStampx_" type="hidden" value="Hrxh2HjDRorBAZWo18hsC0OvbJwyswpDkfTBfNF2NC8=" />
<input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="Questions_1__ID" name="Questions[1].ID" type="hidden" value="76" />
<input id="Questions_1__Title" name="Questions[1].Title" type="hidden" value="Question title displays here?" />
<div>
<input id="Questions_1__Items_item_Value" name="Questions[1].Items.item.Value" type="hidden" value="148" />
<input id="Questions_1__Items_item_Text" name="Questions[1].Items.item.Text" type="hidden" value="Organization Type 1" />
<input data-val="true" data-val-required="The Selected field is required." id="Questions_1__Items_item_Selected" name="Questions[1].Items.item.Selected" type="checkbox" value="true" /><input name="Questions[1].Items.item.Selected" type="hidden" value="false" />
<label for="Questions_1__Items_item_Selected">Organization Type 1</label>
</div>
</div>
</div>
Controller
public class AccountController : BaseController
{
public ActionResult Demographics()
{
return this.View(new DemographicsModel());
}
[HttpPost]
public ActionResult Demographics(DemographicsModel model)
{
return this.View(model);
}
}
On postback, the DemographicsModel is populated with the correct types (I'm using MvcContrib to handle abstract type binding). The List<Question> is populated with all of the correct data including the ID and Title of each question from the hidden fields. However, List<SelectListItem> within each question is set to null.
Update 1
The issue is definitely occurring because the fields are not named correctly. For instance, the "item" field names are being generated like this:
Questions_1__Items_item_Value
When they should really look like this (addition of item index and removal of erroneous "item"):
Questions_1__Items_1__Value
Similarly, the field IDs are being generated like this (addition of item index and removal of erroneous "item"):
Questions[1].Items.item.Value
Instead of:
Questions[1].Items[0].Value
Using Fiddler with the correct IDs being posted back, the model is constructed correctly with all radio buttons and checkboxes in place.
Try the following.
In ChooseManyQuestionModel.cshtml, change #Html.EditorFor(m => m.Items) to:
#Html.EditorForModel(m => m.Items)
Then, in CheckBoxList.cshtml, change #model IEnumerable<SelectListItem> to:
#model SelectListItem
Finally, in each item, modify each lambda expression, and change item to m, then remove the foreeach loop. This will allow the Editor to iterate through the collection, and should give you correct id generation for each element.
When foreach loop is used the ids generated in HTML are all same.
When for look is used the ids generated with the for loops index so binding is happening correctly and all the data is available after post back.
In this scenario, it seems the Helper class is not doing what you want it to do. I would suggest writing your own helper class to name your inputs exactly as you require them to be.

ASP.NET MVC3 C# - edit functionality in detail view of a different controller

I'm trying to create a forum. I'm trying to have the functionality of 'post edit' in 'thread details'
I have the standard OTB Thread index view, and when you click on 'details' it shows the OTB Thread details, I have added a foreach to display the posts relating to that thread underneath.
I'm now struggling with adding/allowing the posts that are displayed underneath to be edited. Specifically show/hide.
In context, all posts are 'hidden' until an administrator clicks a button to 'show' a post, and vice versa
Thread Controller:
public ViewResult Details(int id)
{
tb_SH_Forum_Threads tb_sh_forum_threads = db.tb_SH_Forum_Threads.Single(t => t.Thread_ID == id);
ViewBag.Private_ID = new SelectList(db.tb_SH_Forum_PrivateDesc, "Private_ID", "Private_Desc");
return View(tb_sh_forum_threads);
}
View:
#model Shareholder_Forum.Models.tb_SH_Forum_Threads
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>tb_SH_Forum_Threads</legend>
<div class="display-label">Thread_Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Title)
</div>
<div class="display-label">Thread_Details</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Details)
</div>
<div class="display-label">tb_SH_Forum_Categories</div>
<div class="display-field">
#Html.DisplayFor(model => model.tb_SH_Forum_Categories.Category_Description)
</div>
<div class="display-label">Thread_Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.Thread_Date)
</div>
<div class="display-label">Replies</div>
<div class="display-field">
#Html.DisplayFor(model => model.Replies)
</div>
</fieldset>
#foreach
(var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
<div class ="post">
<fieldset>
<p class="post_details">At #post.Post_Date By #(post.Anon == true ? "Anonymous" : post.Username)
</p>
#post.Post_Desc
</fieldset>
</div>}
<p>
#Html.ActionLink("Back to List", "Index")|
</p>
I think I need to use RenderAction and/or Partial views, but I don't understand. Any advice, or point me in the right direction where I can learn about this.
As always, very much appreciated.
Not certain I understand what you want, but here's how you could do what I think you're asking.
#foreach (var post in Model.tb_SH_Forum_Posts.Where(w => w.Private_ID == 1).OrderBy(o => o.Post_Date))
{
if(post.IsEditable) //however you're determining if they can edit the post. Alternatively display both this and the else and use javascript to toggle which one you show
{
///...Your old view post code
}
else
{
#Html.RenderPartial("EditPost", new {postdata = post})
}
}
Make a model
public class PostDataViewModel
{
public Post PostData
{
get;
set;
}
}
EditPost.cshtml
#model PostDataViewModel
// The editable form and button to submit to SaveForumPost action
Save it with
public virtual ActionResult SaveForumPost(PostaDavaViewModel model)
{
//... save edits
// either return a redirect to Detail, or if you don't want to refresh the page call this with ajax
}

ASP.Net MVC Strongly-Typed Forms

I'm having trouble understanding the difference between the following two Html.BeginForm syntax options:
#using (Html.BeginForm("SubmitSiteSearch", "Home"))
{
#Html.LabelFor(x => x.SearchText, "Quick Search:");
#Html.TextBoxFor(x => x.SearchText);
#Html.SubmitButton("btn-quick-home-search", "Search");
}
#using (Html.BeginForm<HomeController>(x => x.SubmitSiteSearch(Model), FormMethod.Post))
{
#Html.LabelFor(x => x.SearchText, "Quick Search:");
#Html.TextBoxFor(x => x.SearchText, new { id = "quick-home-search" });
#Html.SubmitButton("btn-quick-home-search", "Search");
}
[HttpPost]
public ActionResult SubmitSiteSearch(HomeViewModel model)
{
string _siteSearchText = model.SearchText;
return View(model);
}
The first form creates an instance of HomeViewModel and sets SearchText with the textbox value, while the second form does not.
Can someone explain the difference and/or how these should be used?
The difference is that the second is not part of ASP.NET MVC. You are probably using some 3rd party library such as MVC Futures assembly for example. Assuming you are using the default routes both helpers should generate the same markup:
<form action="/Home/SubmitSiteSearch" method="post">
<label for="SearchText">Quick Search:</label>
<input id="SearchText" name="SearchText" type="text" value="" />
<input id="btn-quick-home-search" name="btn-quick-home-search" type="submit" value="Search" />
</form>

Resources