I have an application where I want Volunteers to be able to help with a Ceremony.
I would like them to be log in and click a button, this brings them to a page where their details appear and a list of Ceremonies they can apply for. I have that page working but I have no way of getting the current user logged in.
Also, for clarification: I have a Volunteer entity which holds the data and then a separate user entity. The username for a Volunteer is the same as their user entity.
I want to:
Compare the Username to the Volunteer Username and get the
VolunteerId.
2.This will then be used to edit/join a ceremony for that particular volunteer.
Here's my Volunteer Controller methods:
// GET:
public ActionResult VolunteerCeremony(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
string userName = string.Empty;
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).SingleOrDefault();
Volunteer v = (Volunteer)(from k in db.Volunteers
where getVolunteerId == k.VolunteerId
select k).SingleOrDefault();
if (v == null)
{
return HttpNotFound();
}
PopulateAssignedCeremonyData(v);
return View(v);
}
// GET:
public ActionResult VolunteerHub()
{
return View();
}
// POST: /Player/VolunteerCeremony/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult VolunteerCeremony(int? id, string[] selectedOptions)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var getVolunteerId = (from u in db.Volunteers
where WebSecurity.CurrentUserName == u.Username
select u.VolunteerId).SingleOrDefault();
var v = (Volunteer)(from k in db.Volunteers
where getVolunteerId == k.VolunteerId
select k).SingleOrDefault();
try
{
UpdateVolunteerCeremonies(selectedOptions, v);
db.Entry(v).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (RetryLimitExceededException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
PopulateAssignedCeremonyData(v);
return View(v);
}
And then my Razor pages, the first which I want the user to click a link to bring them to the edit/join ceremony page:
#model PIMS.Entities.Volunteer
#{
ViewBag.Title = "VolunteerHub";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<li>#Html.ActionLink("Join Ceremony", "VolunteerCeremony", "Volunteers", null, new { id = #model.VolunteerId })</li>
This gives me an error on the new { id = #model.VolunteerId }
Then the page which I want to get to:
#model PIMS.Entities.Volunteer
#using Microsoft.AspNet.Identity
#{
ViewBag.Title = "VolunteerCeremony";
}
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<h2>Apply for Ceremony</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.VolunteerId)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.VolunteerRole, "Volunteer Role", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.VolunteerRole, new { #readonly = "readonly" })
#Html.ValidationMessageFor(model => model.VolunteerRole)
</div>
</div>
</div>
<div class="row">
<div class="col-md-2"> </div>
<div class="form-group col-md-4">
<label class="control-label">Assigned Ceremonies</label>
#Html.ListBox("selectedOptions", (MultiSelectList)ViewBag.SelectedCeremonies, new { #class = "form-control" })
</div>
<div class="form-group col-md-1" style="text-align:center">
<div class="form-group">
<button type="button" id="btnRight" class="btn btn-warning btn-lg">
<span class="glyphicon glyphicon-arrow-right"></span>
</button>
</div>
<div class="form-group">
<button type="button" id="btnLeft" class="btn btn-success btn-lg">
<span class="glyphicon glyphicon-arrow-left"></span>
</button>
<div></div>
</div>
</div>
<div class="form-group col-md-4">
<label class="control-label">Available Ceremonies</label>
#Html.ListBox("availOptions", (MultiSelectList)ViewBag.AvailCeremonies, new { #class = "form-control" })
</div>
<input type="submit" id="btnSubmit" value="Save" class="btn btn-default" />
</div>
<div style="text-align:center;">
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/multisel")
}
Does anyone have any experience with this as it sort of key to my application!
in mvc there is something called session variables, its just like app.config variables, you declare them like this in the controller
Session["Volunteer"] = "volunteer1";
once declared they will remain declared for the entire session.
then you write code for the logoff to reset the Session variable to something that your code handles as no-one logged in or just null.
Related
Context:
I'm trying to build a feature in my MVC Application where an Employer can take an Application submitted by a Student, and convert the information in the Application to create an Employee. However, I'm running into the Cannot perform runtime binding on a null reference error.
Controller:
public ActionResult Onboard (int id)
{
var application = db.Applications.
Include(a=>a.JobPosting.Employer).
Include(a=>a.Student)
.FirstOrDefault(a => a.ApplicationID == id);
return View(application);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Onboard([Bind(Include = "ApplicationID,JobPostingID,StudentID")] Application application)
{
{
if (ModelState.IsValid)
{
db.Employees.Add(new Employee()
{
Student = application.Student,
JobPosting = application.JobPosting,
Employer = application.JobPosting.Employer
});
db.SaveChanges();
return RedirectToAction("Details", "Employees");
}
}
return View(application);
}
View:
#model InTurn_Model.Application
#{
ViewBag.Title = "Onboard";
Layout = "~/Areas/Employers/Views/Shared/_Employers.cshtml";
}
<h2>Onboard</h2>
#using (Html.BeginForm("Onboard","Applications",FormMethod.Post,null))
{
#Html.AntiForgeryToken()
<input id="StudentID" type="hidden" value="#Model.StudentID" />
<input id="JobPostingID" type="hidden" value="#Model.JobPostingID" />
<input id="EmployerID" type="hidden" value="#Model.JobPosting.EmployerID" />
<div class="form-horizontal">
<h4>Employee</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.StudentID, "StudentID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<span>#Model.Student.FirstName #Model.Student.LastName</span>
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.JobPostingID, "JobPostingID", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<span> #Model.JobPosting.Position</span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Hire" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
When I run a debug, the breakpoint on
return View(application)
stores the relevant information from the 1st Onboard controller.
However, the breakpoint on public ActionResult Onboard([Bind(Include = "ApplicationID,JobPostingID,StudentID")] Application application), the 'application' is storing values of 0 for ApplicationID, JobPostingID and StudentID. It's not null technically, but they aren't the correct values.
My question is, what am I doing wrong that the controllers are not passing the correct data? How do I fix this issue?
Is there a better way to achieve this?
I am incredibly new to MVC, and this is the first application that I'm building from the ground up. Any help is appreciated. Thank you!
Looks like I didn't need to use the [HTTPPost] or [ValidateAntiForgerty]. My thought was treating this like a create- but I guess because I'm not actually creating new data- rather transferring one piece of data to another- I don't need to use that.
Here's what I wound up doing:
public ActionResult NewHire(int id)
{
var application = db.Applications.Find(id);
db.Employees.Add(new Employee()
{
StudentID = application.Student.StudentID,
JobPostingID = application.JobPosting.JobPostingID,
EmployerID = application.JobPosting.Employer.EmployerID
});
db.SaveChanges();
return View();
}
I need to run Partial View from action method as a child action method but it redirect me to another view.
1- I tried to use Html.Action("myAction","myController") and I use [ChildActionOnly] data annotation but without any benefit
2- I tried to use Html.RenderAction("myAction", "My Controller") and I change the action method as PartialViewResult and return PartialView("View", myData) but without any benefit.
3- I tried to use JQuery AJAX but without any benefit also.
What I get
What I Expect
** This is the controller
[Authorize(Roles = "Admin")]
[HttpPost]
[ChildActionOnly]
public ActionResult _GetUserRoles(string UserName)
{
SqlParameter param1 = new SqlParameter("#UserName", UserName);
try
{
IList<GetUserRolesViewModel> roles = Identitydb.Database.SqlQuery<GetUserRolesViewModel>("admin.sp_GetUserRoles #UserName",
((ICloneable)param1).Clone()).ToArray().ToList();
return View(roles);
}
catch (Exception ex)
{
ViewBag.Error = ex.ToString();
return RedirectToAction("ErrorSaveData");
}
}
** This is PartialView Code
#model IEnumerable<AMSIdentity.Controllers.GetUserRolesViewModel>
#if (Model == null)
{
<table></table>
}
else
{
<table class="table table-responsive table-striped table-hover table-bordered table-condensed container" style="margin-top: 5%;">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Id)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
</tr>
}
</tbody>
</table>
<br />
#Html.ActionLink("Return Back", "RemoveRoleFromUser", "Manage")
}
** This is Parent Page Code
ViewBag.Title = "RemoveRoleFromUser";
var error = ViewBag.Error as IEnumerable<String>;
}
<h2> Remove role from user </h2>
<ul></ul>
<div class="row container">
<div class="col-md-6">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Username", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("UserName", new { htmlAttributes = new { #class = "form-control" } })
</div>
<hr />
#Html.Label("Role Id", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("RoleId", new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Remove" class="btn btn-default btn-danger" />
</div>
</div>
</div>
}
</div>
<div class="col-md-6">
<div class="row container">
<div class="col-md-12">
<h3> Get user roles </h3>
#using (Html.BeginForm("_GetUserRoles", "Manage", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Username", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("UserName", new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Get rules" class="btn btn-default btn-success" id="btnRules"/>
</div>
</div>
</div>
}
</div>
</div>
<div class="row container">
<div class="col-md-12">
#Html.Partial("_GetUserRoles")
</div>
</div>
</div><!--Second Column-->
</div> <!--End of row-->
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
** This is the view Model
public class GetUserRolesViewModel
{
[DisplayName("Username")]
public string Name { get; set; }
[Key]
[DisplayName("Role Id")]
public string Id { get; set; }
}
** This is AJAX Code that i used to run partial view
<script type="text/javascript">
//$(document).ready(function ()
//{
$("#btnRules").click(function (e)
{
var UserName = $("#UserName").val();
$.ajax({
url: '/Manage/_GetUserRoles',
dataType: 'html',
data:{"UserName": UserName},
success: function (data)
{
$('#listRules').html(data);
},
error: function (xhr, ajaxOptions, thrownError)
{
alert('Failed to retrieve rules.');
}
});
});
//});
</script>
** Route Picture
Route Config Picture
I expect to run the Action Method (_GetUserRoles) Partially in the same view of RemoveRoleFromUser.
your return must be a PartialView() and not a view. view() will return a complete view where as PartialView() will return a partial view. So yo need to change your
return View();
to
return PartialView("YourPartialViewName");
and if you need to pass a parameter to your partial view
return PartialView("YourPartialViewName",roles);
if you are rendering a partial view from your View them you can use Html hepler
return PartialView("~/views/ABC/PartialViewName.cshtml", Yourmodel);
I am assuming that your ajax call hits the controller action. And the partial view needs to be placed in the parent view code at-
<div class="row container">
<div class="col-md-12">
#Html.Partial("_GetUserRoles")
</div>
</div>
Based on these assumptions, you need to change few things in your code:
return PartialView instead of View from the action. Something like this:
return PartialView("_GetUserRoles", roles);
// the partial view name mentioned here is just a sample based on the context.
//You need to give your partial view's name here.
add an id attribute to the div inside which you have written #Html.Partial("_GetUserRoles"). Something like this:
<div class="row container">
<div class="col-md-12" id="userRoles">
</div>
</div>
within the success function in the ajax method, you need to use the id attribute set in above step and populate the data inside it. Something like this:
success: function (data)
{
$('#userRoles').html(data);
}
Install the Microsoft.Jquery.Unobtrusive.Ajax and Microsoft.Jquery.Unobtrusive.Validation in your project. Then add the reference of these two within your view file. Something like this:
#section scripts{
#Scripts.Render("~/Scripts/jquery{version}.js")
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
}
This way you should be able to see the partial view within your existing view itself.
Here is the answer
I use ViewData[""] rather than PartialView and i put one parameter in the same action result to check which view i will use.
** Action Method RemoveRoleFromUserConfirmed
public ActionResult RemoveRoleFromUserConfirmed(string UserName, string RoleId, string btnval)
{
if (btnval == "Remove")
{
if (UserName == null && RoleId == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
SqlParameter param1 = new SqlParameter("#RoleId", RoleId);
SqlParameter param2 = new SqlParameter("#UserName", UserName);
try
{
Identitydb.Database.ExecuteSqlCommand("admin.sp_RemoveUserFromRole #RoleId, #UserName", param1, param2);
}
catch (Exception ex)
{
ViewBag.Error = ex.ToString();
return RedirectToAction("ErrorSaveData");
}
return RedirectToAction("Roles");
}
else if (btnval == "Get Rules")
{
SqlParameter param1 = new SqlParameter("#UserName", UserName);
try
{
IList<GetUserRolesViewModel> roles = Identitydb.Database.SqlQuery<GetUserRolesViewModel>("admin.sp_GetUserRoles #UserName",
((ICloneable)param1).Clone()).ToArray().ToList();
string result = "";
foreach (var item in roles)
{
result += "<tr>"
+ "<td>" + item.Name + "</td>"
+ "<td>" + item.Id + "</td>"
+ "</tr>";
}
ViewData["getrules"] = result;
return View();
}
catch (Exception ex)
{
ViewBag.Error = ex.ToString();
return RedirectToAction("ErrorSaveData");
}
}
return View();
}
** This is the view
#{
ViewBag.Title = "RemoveRoleFromUser";
var error = ViewBag.Error as IEnumerable<String>;
}
<h2> Remove role from user </h2>
<ul></ul>
<div class="row container">
<div class="col-md-6">
#using (Html.BeginForm("RemoveRoleFromUser", "Manage", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Username", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("UserName", new { htmlAttributes = new { #class = "form-control" } })
</div>
<hr />
#Html.Label("Role Id", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("RoleId", new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Remove" name="btnval" class="btn btn-default btn-danger" />
</div>
</div>
</div>
}
</div>
<div class="col-md-6">
<div class="row container">
<div class="col-md-12">
<h3> Get user roles </h3>
#using (Html.BeginForm("RemoveRoleFromUser", "Manage", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.Label("Username", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.Editor("UserName", new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Get Rules" name="btnval" class="btn btn-default btn-success" id="btnRules" />
</div>
</div>
</div>
}
</div>
</div>
<div class="row container">
<div class="col-md-12" id="listRules">
<!--Data Come from ViewData-->
<table class="table table-responsive table-striped table-hover table-bordered table-condensed container" style="margin-top: 5%;">
<thead>
<tr>
<th>
Role Name
</th>
<th>
Role Id
</th>
</tr>
</thead>
<tbody>
#Html.Raw(ViewData["getrules"])
</tbody>
</table>
</div>
</div>
</div><!--Second Column-->
</div> <!--End of row-->
<div>
#Html.ActionLink("Back to List", "Roles")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
I put the name of button same in two buttons (remove and get rules)
after that i checked the value of the button in ActionMethod and if it
is remove it will do some function and if it is get rules i will use
ViewData[""] to put the view.
Regards,
Ali Mosaad
Software Developer
I would suggest changing
return View(roles);
to
return PartialView(roles);
or
return PartialView("_GetUserRoles", roles);
Using ajax
$.ajax({
url: '/Manage/_GetUserRoles',
dataType: 'html',
data:{"UserName": UserName},
success: function (data)
{
$('#listRules').html(data);
},
error: function (xhr, ajaxOptions, thrownError)
{
alert('Failed to retrieve rules.');
}
});
...
<div class="row container">
<div id="listRules" class="col-md-12">
#Html.Partial("_GetUserRoles", Model.Roles)
</div>
</div>
I have a page where i am displaying image, id, name and address. I have added checkbox and multiple submit buttons to delete update or add new records.
But when I click on any submit buttons i am getting unhandled exception error. (for example I have selected a checkbox and clicked delete button my control is going to Mycontroller from view and to the delete switch case. It is deleting the record but again when it is coming back to view I am getting the NullReferenceException.)
View :
#using (Html.BeginForm("MyAction", "MyController", FormMethod.Post))
{
#if (Model.Count> 0) // .NullReferenceException
{
#foreach (var MyDB in Model)
{
<div class="col-md-2">
<img src="#Url.Content(photos.photo_url)" style="width:100px; height:100px;" />
</div>
Html.LabelFor(model => MyDB.ID, new
{
#class = "control-label col-md-2"
})
<div class="col-md-2">
#Html.EditorFor(model => MyDB.ID)
#Html.ValidationMessageFor(model => MyDB.ID)
</div>
#Html.LabelFor(model => MyDB.name, new
{
#class = "control-label col-md-2"
})
<div class="col-md-2">
#Html.EditorFor(model => MyDB.name)
#Html.ValidationMessageFor(model => MyDB.name)
</div>
#Html.LabelFor(model => MyDB.address, new
{
#class = "control-label col-md-2"
})
<div class="col-md-2">
#Html.EditorFor(model => MyDB.address)
#Html.ValidationMessageFor(model => MyDB.address)
</div>
<div class="col-md-1">
input type="checkbox" class="checkboxes" value="#MyDB.id" name="id" />
</div>
}
}
}
<div class="col-md-offset-2 col-md-10">
<input type="submit" name="submitButton" value="UPDATE" />
<input type="submit" name="submitButton" value="ADD" />
<input type="submit" name="submitButton" value="DELETE" />
</div>
Controller :
public ActionResult MyController(IEnumerable<int> id, string submitButton)
{
switch (submitButton)
{
case "DELETE":
foreach (var item in id)
{
var delete = _db.MyDB.FirstOrDefault(s => s.id == item);
if (delete != null)
{
_db.MyDB.Remove(delete);
}
}
break;
case "ADD":
if (!ModelState.IsValid)
{
return RedirectToAction("ADDRecordPage", new
{
id
});
}
if (id == null)
{
return RedirectToAction("ADDRecordPage", new
{
id
});
}
break;
case "UPDATE" :
ViewBag.Message = "UPDATE";
break;
}
_db.SaveChanges();
ViewBag.Message = "Saved";
return View();
}
I found out what mistake I did. Inside controller i added return View(); it was returning null. so changed to return RedirectToAction("MyAction", new { id }); instead of return View();
I followed an online tutorial to dynamically add items to a bound list model using ajax, which works perfectly. (http://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/comment-page-2/#comment-68909)
My question is, how would I correctly remove items from the list?
Right now what I have done is add a delete link which when clicked removes the item from the view. However, when I submit the form I noticed that the modelState is no longer valid and it has null entries for the item that was removed from the view. So I guess the model is not being updated.
Test.cshtml
#model TesterManager.Models.Test
<div class="form-group">
#Html.LabelFor(model => model.Software, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<div class="form-group">
<div class="col-md-5">
#Html.DropDownListFor(m => m.Software, TesterManager.Models.Helper.GetTestSoftwares(), "Choose a USB Card", new { #class = "form-control" })
#Html.ValidationMessageFor(model => model.Software, "", new { #class = "text-danger" })
</div>
<div class="col-md-5">
#Html.EditorFor(model => model.Version, new { htmlAttributes = new { #class = "form-control", #title = "Enter a USB FW Version", #placeholder = "Enter a USB FW Version" } })
#Html.ValidationMessageFor(model => model.Version, "", new { #class = "text-danger" })
</div>
<div class="col-md-2">
Delete
</div>
</div>
</div>
</div>
AdminTesterConfigurations.cshtml (snippet):
#model TesterManager.Models.AdminTesterConfigurations
<div class="form-group">
<div class="col-md-6">
....
</div>
</div>
<hr />
<div class="form-group">
<div class="col-md-12">
<h3>Test Software</h3>
<div id="test-list">
#Html.EditorForMany(x => x.Tests, x => x.Index)
</div>
<input type="button" id="add-test" value="Add" />
</div>
</div>
RequestEditViewModel.cshtml:
#model TesterManager.Models.RequestEditViewModel
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.EditorFor(model => model.ShippingLocation)
#Html.EditorFor(model => model.RequesterTesterConfigurations)
#Html.EditorFor(model => model.AdminTesterConfigurations)
<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>
Edit.cshtml:
#model TesterManager.Models.RequestEditViewModel
#Styles.Render("~/Content/Edit")
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section Scripts
{
<script>
jQuery(document).ready(function ($) {
$('#add-test').on('click', function () {
jQuery.get('/TesterManager/Request/AddTest').done(function (html) {
$('#test-list').append(html);
});
});
});
</script>
}
#using (Html.BeginForm())
{
<h2>Edit</h2>
#Html.AntiForgeryToken()
#Html.EditorFor(x => x);
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
RequestController.cs
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(RequestEditViewModel request)
{
if (ModelState.IsValid)
{
Request domainRequest = new Request(request);
requests.Add(domainRequest);
return RedirectToAction("Index");
}
return View(request);
}
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult AddTest()
{
var request = new RequestEditViewModel();
request.AdminTesterConfigurations.Tests.Add(new Test());
return View(request);
}
I realized that the problem was that when I would remove the item from the list in the view, I was not removing the hidden input for the collection indexer as well. I updated the code to remove the hidden input and it works fine now.
While developing an ASP.NET MVC 4 application I ran into a problem updating a saved image.
Basically when the user selects the edit tab, their re-directed to the content they previously entered.
One such item of that content is an image, and when in the edit menu they can choose to replace the existing image.
I have the other content updating correctly but the image remains the same, when I place a breakpoint on the "edit" ActionResult, it show the image value for the passing model as null? newsArticle.ArticleImage = Null
FYI - Image is saved as a byte array.
Am I missing something ?
Controller....
[HttpPost]
public ActionResult Edit(NewsArticle newsArticle, int id, HttpPostedFileBase Article)
{
try
{
if (ModelState.IsValid)
{
NewsArticle savedArticle= _newsArticle.Get(id);
savedArticle.Body = newsArticle.Body;
savedArticle.Title = newsArticle.Title;
if (newsArticle.ArticleImage == null)
{
newsArticle.ArticleImage = savedArticle.ArticleImage;
}
else
{
using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
{
newsArticle.ArticleImage = binaryReader.ReadBytes(Request.Files[0].ContentLength);
}
savedArticle.ArticleImage = newsArticle.ArticleImage;
}
if (newsArticle.ImageName == null)
{
newsArticle.ImageName = savedArticle.ImageName;
}
else
{
string imgeName = Path.GetFileName(Article.FileName);
savedArticle.ImageName = imgeName;
}
_uow.SaveChanges();
return RedirectToAction("Index");
}
}
catch (System.Data.DataException)
{
//Log th error(add a variable name after DataExpection)
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(newsArticle);
}
View..........
#using (Html.BeginForm("Edit", "Admin", FormMethod.Post, new { enctype = "multipart/form-data", #class = "form-horizontal", id = "newsEditForm" }))
{
#Html.ValidationSummary()
#Html.HiddenFor(model => model.ID)
<div class="control-group">
<label class="control-label">Posted on :</label>
<div class="controls">
<span class="text">#Model.DateCreated.Value.ToShortDateString()</span>
#*#Html.LabelFor(n => n.DateCreated)*#
</div>
</div>
<div class="control-group">
<label class="control-label">#Html.LabelFor(n => n.Title)</label>
<div class="controls">
#Html.TextBoxFor(n => n.Title, new { #class = "span4 m-wrap", rows = 1 })
</div>
</div>
<div class="control-group">
<label class="control-label">#Html.LabelFor(n => n.Body)</label>
<div class="controls">
#Html.TextAreaFor(n => n.Body, new { #class = "span12 ckeditor m-wrap", rows = 4 })
</div>
</div>
<div class="control-group">
<label class="controls">#Html.DisplayTextFor(model => model.ImageName)</label>
<div class="span4 blog-img blog-tag-data">
<div class="editor-field">
<input type="file" name="Article" id="ArticleImage" />
</div>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn green" id="submitnews"><i class="icon-ok"></i>Submit</button>
#Html.ActionLink("Cancel", "ArticleList", "Admin", null, new { #class = "btn blue" })
#*<button type="button" class="btn blue" onclick="location.href='ArticleList','Admin'">Cancel</button>*#
</div>
}