I am trying to send viewbag from action method to view. When first page loads viewbag value will be null. when I call CheckPermissions action method viewbag gets some value and it will return the same view that time viewbag contains some value and now I want to compare viewbag value with another value. I tried but following error appearing. Cannot perform runtime binding on a null reference.
This is my Index view code.
#model c3card.Models.GroupPermissionVM
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm())
{
#Html.LabelFor(m=>m.GroupID)
#Html.DropDownListFor(m => m.GroupID, Model.GroupList, "Please select", new { id = "ddlgrp" })
foreach(var permission in Model.Permissions)
{
if (ViewBag.marlid.equals(permission))
{
<label>
#Html.RadioButtonFor(m => m.perm_id, permission.perm_id, new {#checked="true"})
<span>#permission.perm_levelname</span>
</label>
}
else
{
<label>
#Html.RadioButtonFor(m => m.perm_id, permission.perm_id)
<span>#permission.perm_levelname</span>
</label>
}
}
This is my action method
public ActionResult CheckPermissions(int id)
{
var groups = db.tm_grp_group.Where(a => a.grp_isactive == true);
var permissions = db.tm_perm_level;
GroupPermissionVM model = new GroupPermissionVM
{
marlid=db.ts_grp_perm_mapping.Select(p=>p.grp_id==id).Count(),
GroupList = new SelectList(groups, "grp_id", "grp_name"),
Permissions = permissions.Select(p => new PermissionVM
{
perm_id = p.perm_id,
perm_levelname = p.perm_levelname
})
};
ViewBag.marlid = db.ts_grp_perm_mapping.Select(p => p.grp_id == id).Count();
return View("Index",model);
}
Any suggestion why I am not able to compare values inside if condition? Thanks in advance. This line causing me error if (ViewBag.marlid.equals(permission))
I edited as follows
foreach(var permission in Model.Permissions)
{
if(Model.marlid==permission.perm_id)
{
<label>
#Html.RadioButtonFor(m => m.perm_id, permission.perm_id,new { #checked = true } )#Model.marlid.ToString()
<span>#permission.perm_levelname</span>
</label>
}
You can change the code given below
if(ViewBag.marlid != null && Model.Permissions != null)
{
foreach(var permission in Model.Permissions)
{
if(ViewBag.marlid == permission.perm_id)
{
<label>
#Html.RadioButtonFor(m => m.perm_id, permission.perm_id,new { #checked = true } )#Model.marlid.ToString()
<span>#permission.perm_levelname</span>
</label>
}
}
}
Hope this helps.
Related
My issue: the dropdownlistfor is not selecting the correct value of string when loading the page. Here is the code and view:
Surcharges.html
#model IEnumerable<IEnumerable<string>>
#{
ViewBag.Title = "Surcharge Management";
}
<div id="mainTitleDiv" class="mainTitle">
<span style="display:inline-block;">#ViewBag.Title</span>
</div>
<br />
<table class="table">
#{
int i = 0;
foreach (var surcharge in Model)
{
int j = 0;
<tr>
#foreach (var item in surcharge)
{
if (i == 0)
{
#:<th>#Html.DisplayFor(model => item)</th>
}
else
{
if (j == 0)
{
#:<th>#Html.DisplayFor(model => item)</th>
}
else
{
#:<td>
if (!string.IsNullOrEmpty(item) && (i == 2)) // Type
{
#Html.DropDownListFor(x => item, new List<SelectListItem>
{
new SelectListItem() {Text = "Fixed Amount", Value ="0"},
new SelectListItem() {Text = "Percentage", Value ="1"}
}, new { style = "width:100%; height:34px;" } )
}
else
{
#Html.EditorFor(model => item, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => item, "", new { #class = "text-danger" })
}
#:</td>
}
j++;
}
}
</tr>
i++;
}
}
AdminController.cs
public ActionResult Surcharges()
{
if (!User.Identity.IsAuthenticated)
{
return RedirectToAction("Login", "Account");
}
int userId = User.Identity.GetUserId<int>();
var query = db.Surcharges.Where(x => x.UserId == userId).OrderBy(x => x.Id).ToList();
IEnumerable<IEnumerable<string>> surcharges = Utility.Pivot<string>(Utility.GetSurchargeList(query));
return View(surcharges);
}
Surcharges page
Surcharge
S2 and D1 have the string value "1" and not selected by the dropdownlist.
What am I doing wrong ?
Do I need a model to post the data edited back to the server ?
What should the correct model look like ?
Thanks
Thanks, Stephen. My ASP.NET MVC project requirement is to design a page that looks like this image:
Surcharge Page
and my Surcharge table and data look like this:
Surcharge Table
What is your suggestion regarding the model that properly works and binds to the table ?
Is it better to use a grid with Edit and Delete buttons instead of the foreach table ?
I'm looking for the best model that actually allows each row to be edited and saved into the table (dropdownlist for the Type field).
I have a ProjectDetailsViewModel that has a Project object in it. I want to make only one View for the Update form and for the Insert Form. In other words, if the server does not return a project to the View, then the form should be empty and if a project gets returned to the view, then the values should be filled in and the user can change or add...
The question is how do I return a null project to the View when I click the "Add Project" button? I have to return a projectId to the View...
This is what I tried so far but I keep on getting the error:"The resource cannot be found." Thanks.
This is the ProjectDetailsView:
#using DCMS.Models.Projects
#model DCMS.Models.Projects.DataViewModels.ProjectDetailsViewModel
#{
ViewBag.Title = "Project Details";
}
#using (Html.BeginForm("UpdateProjectView", "Project", FormMethod.Post))
{
#*<div class="errormessage">#Html.ValidationSummary(false)</div>*#
if (Model.ReturnMessage != null || Model.ReturnMessage != "")
{
<div class="InfoMessageOuter">
<div class="InfoMessageMiddle">
<div class="InfoMessageInner">#Model.ReturnMessage</div>
</div>
</div>
}
#Html.HiddenFor(m => m.Project.ClientId)
#Html.HiddenFor(m => m.Project.Id)
#Html.HiddenFor(m => m.Project.ModeledOn)
<br/>
#*<h2 style="font-size: 20px; margin: 5px;">#Model.Project.Client.ClientName </h2>*#
<div>
<table style="margin: 0 30px;">
This is the Controller:
[HttpGet]
public ActionResult GetProjectView(string returnMessage, int? id = null)
{
ProjectDetailsViewModel projectDetails;
if (id == null)
{
projectDetails = new ProjectDetailsViewModel();
return View("ProjectView",projectDetails);
}
projectDetails = ProjectDataAccess.GetProjectDetails(id.Value);
if (projectDetails == null) return PartialView("Error");
projectDetails.ReturnMessage = returnMessage;
return View("ProjectView", projectDetails);
}
[HttpPost]
public ActionResult UpdateProjectView(ProjectDetailsViewModel projectViewModel)
{
if (!ModelState.IsValid)
{
projectViewModel.ReturnMessage = #"Error! Update Failed.";
return GetProjectView(projectViewModel.ReturnMessage, projectViewModel.Project.Id);
}
if (projectViewModel.Project.Id != null)
{
var success = ProjectDataAccess.UpdateProject(projectViewModel.Project);
projectViewModel.ReturnMessage = success ? #"Project Updated Successfully" : #"Error! Update Failed";
}
else if(projectViewModel.Project.Id == null)
{
var success = ProjectDataAccess.AddProject(projectViewModel.Project);
projectViewModel.ReturnMessage = success ? #"Project Added Successfully" : #"Error! Insert Failed";
}
return GetProjectView(projectViewModel.ReturnMessage, projectViewModel.Project.Id);
}
you should use RedirectToAction like this
return RedirectToAction("GetProjectView", new{returnMessage=projectViewModel.ReturnMessage,id = projectViewModel.Project.Id});
because when you use return GetProjectView it will return to the same action UpdateProjectView but if you use RedirectToAction it will go to GetProjectView action and it will return the view instead of going back to UpdateProjectView action. you can also check this Controller.RedirectToAction Method (String, Object)
Is it possible to enable model binding along with a posted data from a form?
I have a collection property that I want to iterate in a foreach loop to save each selected item in the collection:
<div class="form-group">
#Html.LabelFor(m => m.Users, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#{
List<ApplicationUser> allUsers = ViewBag.AllUsers;
bool assigned;
}
<div>
#foreach (var user in allUsers)
{
//here I want to render all users, and only the users who are in the task, have a checked checkbox
assigned = Model.Users.Select(u => u.Id).Contains(user.Id);
<input type="checkbox" name="asndUsers" value="#user.Id" id="#user.Id" #Html.Raw(assigned ? "checked" : "") /> <label style="font-weight: normal;" for="#user.Id">#user.UserName</label><br />
}
</div>
</div>
</div>
//fields updated with model binding:
<div class="form-group">
#Html.LabelFor(m => m.Status, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(m => m.Status, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(m => m.Status)
</div>
</div>
this is the Edit action post method:
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Title,Description,DueDate,Status")] UserTask task, string[] asndUsers)
{
if (ModelState.IsValid)
{
task.Users = new List<ApplicationUser>();
foreach (var item in asndUsers)
{
var user = context.Users.Find(item);
task.Users.Add(user);
}
context.Entry(task).State = EntityState.Modified;
context.SaveChanges();
return RedirectToAction("Index");
}
return View(task);
}
it works when I debug, I see the new posted data has merged with the bound data.
but when the request redirected to the Index view, there is no change after editing an item, this is the Index action method:
public ActionResult Index(int? taskId)
{
var viewModel = new TasksUsers();
viewModel.Tasks = context.Tasks.Include(x => x.Users);
if (taskId != null)
{
viewModel.Users = viewModel.Tasks.Where(t => t.Id == taskId).Single().Users;
ViewBag.Row = taskId;
}
return View(viewModel);
}
Original answer
The proper way of updating the related entities is loading them first,
so I used eager loading to redefine the incoming task parameter as
follows:
task = context.Tasks.Include(t => t.Users).Single(s => s.Id == task.Id); Note that `Find` can't be used with `Include` so I used
Single.
That resolved the problem of updating the Users entity
this was wrong,
the proper way is to use explicit binding instead of implicit binding (TryUpdateModel())
The task that is posted back is no longer tracked by the DbContext. Try to Attach the task to the DbSet in the Edit action:
context.Tasks.Attach(task);
if (task.Users == null) {
task.Users = new List<ApplicationUser>();
}
foreach (var item in asndUsers) {
var user = context.Users.Find(item);
task.Users.Add(user);
}
// may be important because Attach() sets the State to 'Unchanged'?
context.Entry(task).State = EntityState.Modified;
context.SaveChanges();
As a side note, you can pass parameters when you call RedirectToAction. (Only do this if you want to pass the id of the edited task to the Index action):
return RedirectToAction("Index", new { taskId = existingTask.Id });
// ^^^^^^
// must match parameter name of Index action
I am using BeginForm and the initial value of one of the Dropdown's is not being set properly. The value is held in a SelectLitemItem and is correctly shown in the preceding Table (in the Index view). The available values provided for list are also correct. It always defaults to "Create" which has a value of "1" even when it should be "Update" which has a value of "2".
The Model.RuleType.Value is shown correctly if I just display it on the form.
I cannot see what I'm doing wrong. I can see no duplicate ID/ Name and have tried including a Hidden field.
There is another dropdown that happens to use a common value for both Value and Text and that works.
Any ideas?
Thanks.
#model AMS.Web.Areas.Admin.Models.RuleActionModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true) #Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.RuleType, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Partial("Partials/_RuleTypeDropdown") #Html.ValidationMessageFor(model => model.RuleType)
</div>
</div>
RuleTypeDropdown
#using Kendo.Mvc.UI;
#(Html.Kendo().DropDownList()
.Name("RuleType")
.DataTextField("Text")
.DataValueField("Value")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("RuleTypeList", "List", new { Area = "Admin" });
});
})
)
Model
public class RuleActionModel
{
public RuleActionModel() { }
public RuleActionModel(RuleAction ruleAction)
{
...
RuleType = new SelectListItem()
{
Value = ruleAction.RuleType.ToString(),
Text = ((RuleType)(ruleAction.RuleType)).EnumToString()
};
}
[Display(Name = "Type")]
public SelectListItem RuleType { get; set; }
Controller
public ActionResult Edit(Guid? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
RuleAction ruleAction = UnitOfWork.RuleActionRepository.FirstOrDefault(x => x.ID == id);
if (ruleAction == null)
{
return HttpNotFound();
}
var model = new RuleActionModel(ruleAction);
return View(model);
}
I have search form to search by : site, user, status and date. After searched I will do Reject, Re-submit or Approve to call the controller action for update the status in the database. My code are as below:
/// View :
#Html.ValidationMessage("CustomError")
#Html.ValidationSummary(true)
#using (Html.BeginForm()) // Begin Form
{
<table>
<tr>
<td>Site:</td>
<td>#Html.DropDownList("sites", (IEnumerable<SelectListItem>)ViewBag.sites, "-- ALL --", new { style = "width: 300px;" })</td>
<td>Status:</td>
<td>#Html.DropDownList("status", (IEnumerable<SelectListItem>)ViewBag.status, "-- ALL --", new { style = "width: 150px;" })</td>
<td>PO No:</td>
<td>#Html.TextBox("PONumber", null, new { style = "width:150px" })</td>
</tr>
<tr>
<td>User: </td>
<td>#Html.DropDownList("user", (IEnumerable<SelectListItem>)ViewBag.user, "-- ALL --", new { style = "width: 300px;" })</td>
<td>Department:</td>
<td>
#Html.DropDownList("department", (IEnumerable<SelectListItem>)ViewBag.department, "-- ALL --", new { style = "width: 150px;" })
</td>
<td>Transaction Date:
</td>
<td>
#*<input type="text" id="TransactionDate" name="TransactionDate" style="width:210px" />*#
#*#Html.TextBox("TransactionDate", null, new { #class="datefield", style = "width:150px", #Value = DateTime.Now.ToShortDateString() })*#
#Html.TextBox("TransactionDate", null, new { #class="datefield", style = "width:150px" })
</td>
</tr>
</table>
<input type="submit" value="Search" />
// Here is the search result table
<input type="submit" value="Re-Submit" name="action" />
<input type="submit" value="Approve" name="action" />
<input type="submit" value="Reject" name="action" />
} // End Form
//// Controller
// HTTP Get
public ActionResult POHeader(string sites, string user, string department,
string status, string PONumber, string TransactionDate, bool IsRedirectAction = false)
{
// Populate Dropdown List
GetSiteDropdownList(SiteId);
GetUserDropdownList(UserId);
GetDepartmentDropdownList(DepartmentId);
GetStatusDropdownList(StatusId);
var PO = from p in db.X_PO_HDR
select p;
// Get Selected Site
if ((!string.IsNullOrEmpty(sites)) || ((TempData["selectedsite"] != null)))
{
if (sites.Length > 0)
{
if (IsRedirectAction)
{
SiteId = (string)TempData["selectedsite"];
//sites = SiteId;
}
else
{
SiteId = sites;
TempData["selectedsite"] = SiteId;
}
// Get Selected Site
PO = PO.Where(p => p.Site_Id == SiteId);
}
}
if (!string.IsNullOrEmpty(user) || ((TempData["selectedUser"] != null)))
{
if (user.Length > 0)
{
if (IsRedirectAction)
{
UserId = (string)TempData["selectedUser"];
}
else
{
UserId = user;
TempData["selectedUser"] = UserId;
}
// Filter by User
PO = PO.Where(p => p.Created_By == UserId);
}
}
// Get Selected Department
if (!string.IsNullOrEmpty(department) || ((TempData["selectedDepartment"] != null)))
{
if (department.Length > 0)
{
if (IsRedirectAction)
{
DepartmentId = (string)TempData["selectedDepartment"];
}
else
{
DepartmentId = department;
TempData["selectedDepartment"] = DepartmentId;
}
// Filter by Department
PO = PO.Where(p => p.Purch_Dept == DepartmentId);
}
}
PO = PO.OrderBy(o => o.Txn_DT);
// check if TempData contains some error message and if yes add to the model state.
if (TempData["CustomError"] != null)
{
ModelState.AddModelError(string.Empty, TempData["CustomError"].ToString());
}
return View(PO.ToList());
}
/// HttpPost Action
[HttpPost, ActionName("POHeader")]
[MultiButton(MatchFormKey = "action", MatchFormValue = "Reject")]
public ActionResult Reject(int[] selectedList)
{
string var1 = collection["sites"];
UpdateListStatus(selectedList, "X", "Rejected");
TempData["CustomError"] = selectedList.Count().ToString() + " record(s) has been successfully " + ActionString + "!";
return RedirectToAction("POHeader", new { IsRedirectAction = true });
}
Question: How to get back the search values?
1. Do I need to pass all the parameters again at HTTPPost Action? (any better way to solve?)
2. CustomError message is not working. (Message appear after next search is done)
Thanks,
Si Thu
I would start out by binding the View to a model. By doing this you can pass the entire model back to your method, then if there are issues with the form and you need to show it again with the values, you just return back the view along with the model you sent.
[HttpPost]
public ActionResult POHeader(FormModel model)
{
if (ModelState.IsValid)
{
// Do whatever you want to do and redirect to wherever you want to go from here.
}
// If the Model is invalid then simply return back the view along with the invalid model.
return View(model)
}
See the following article for more information on Model Binding
http://www.codeproject.com/Articles/159749/ASP-NET-MVC-Model-Binding-Part1
Here is another article on Client Side Model validation
http://www.codeproject.com/Articles/718004/ASP-NET-MVC-Client-Side-Validation