How can I put my fieldsets side-by-side? - asp.net-mvc-3

would like to put fieldSets side-by-side on my “Edit” page because I have so many fields on the page. Since I couldn’t find an easy fix, I decided to put the fields in a table. This worked fine except for when I click on the “Save” button I get this error:
“Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.”
Questions: How can I put my fieldsets side-by-side or make my table to work with the save button?
Thanks for any help.
Here's the edit methods of my controller:
public ActionResult Edit(int id)
{
CourseProgress courseprogress = db.CourseProgresses.Find(id);
ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "Name", courseprogress.CourseId);
ViewBag.TeacherId = new SelectList(db.Teachers, "TeacherId", "Name", courseprogress.TeacherId);
var PdfReportProperties = new PdfReport();
return View(courseprogress);
}
//
// POST: /ProgressManager/Edit/5
[HttpPost]
public ActionResult Edit(CourseProgress courseprogress)
{
if (ModelState.IsValid)
{
db.Entry(courseprogress).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("ProgressRecord");
}
ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "Name", courseprogress.CourseId);
ViewBag.TeacherId = new SelectList(db.Teachers, "TeacherId", "Name", courseprogress.TeacherId);
return View(courseprogress);
}

The most likely reason you are getting that error is that as you don't have a field for the ID of your model in the form, once you hit the SAVE button, the object you are editting has its ID property in null.
To solve it, use a hidden field holding the ID of the model, so that once the form post its fields it became mapped in your controller model object.
This problem has nothing to do with the position or layout of your fields.

Related

Use the same instance of model view across views in ASP MVC 3

I have two views : the first one has a form which when submitted, it fills in a model view (QuizzModelView).
Now after submitting, I am redirected to another view which also has a form that I want to submit. The problem is that I want to use the same QuizzModelView for the two views. That means, when submitting the second form, I want also to submit the values of the previous form. I can do this by creating hidden inputs which take the values that come from the first view.
Is there a way to do it without hidden inputs.
Thanks
EDIT :
To explain more:
My model view contains : QuizzModelView.field1, QuizzModelView,.field2
1st step : View1 will fill in QuizzModelView.field1
2nd step : I am redirected to view2
3rd step : View2 will fill in QuizzModelView.field2
Now I want to be able to get QuizzModelView.field1 and QuizzModelView.field2. But I get Only QuizzModelView.field2 because QuizzModelView.field1 is lost when submitting View2
Here are my actions :
[HttpPost]
public ActionResult TAFPart2PopupEvents(QuizzModelView model)
{
return PartialView("PartialViews/_TAFPart2PopupEvents", model);
}
[HttpPost]
public ActionResult TAFPart3PopupEvents(QuizzModelView model)
{
// here I want to use
// model.field1 and model.field2
}
Technically (pedantically), you won't be able to use the same instance of the model. However, you can put it in the session and pass across the redirects. Session has the advantage of not getting tampered with as easily as hidden fields. Plus you wouldn't have to actually bind the whole model for each step - just the single field from each step:
[HttpPost]
public ActionResult TAFPart2PopupEvents(string field1)
{
QuizzModelView model = new QuizzModelView();
model.Field1 = field1
Session["Quiz"] = model;
return PartialView("PartialViews/_TAFPart2PopupEvents", model);
}
[HttpPost]
public ActionResult TAFPart3PopupEvents(string field2)
{
var model= (QuizzModelView )Session["Quiz"];
// Fill in field2 here
model.Field2 = field2;
}
Edit: To address Brian's comment with some actual detail -
This method with sessions is less susceptible to data tampering than hidden fields, if that's a concern at all. With hidden fields in the view, a malicious user could easily overwrite previous data. Depending on the size of your model, hidden fields could bloat up the view a bit too.
Sessions also have the drawback of expiring. Here's a simple way to handle expirations. If this is called via Ajax, then you'll have to pass an error message back to the client instead to handle there.
[HttpPost]
public ActionResult TAFPart3PopupEvents(string field2)
{
var model= Session["Quiz"] as QuizzModelView;
if (model == null)
{
// Add some kind of message here.
// TempData is like Session, but only persists across one request.
TempData["message"] = "Session Expired!";
return RedirectToAction("Index");
}
// Fill in field2 here
model.Field2 = field2;
....
}
If you want your TAFPart3PopupEvents action to have access to the data, you need to store it some place. There are many different options (session, querystring, db), but I think a hidden input (in general) is the easiest.

MVC ddl value after postback

I have a ddl which is populated with hours of day 01-23. This is on a form which is used to book an item of equipment. The hour is populated to a db field. The issue is this, when the booking form is opened to alter the time the ddl shows the hour that was booked, when changed though and the form is submitted the value passed on post is the initial value from db not the new selected hour.
this is the basic pieces of code. any idea why the newly selected ddl value is not passed to the model??
View
<%= Html.DropDownList("ddl_Hour", Model.ddlHour,
new { #class = "DropDown", style = "width: 40px” })%>
Model
private string _ddlHourSelectedValue = "0";
public SelectList ddlHour
{
get
{
return (new System.Web.Mvc.SelectList(_ddlHour, "intValue", "Text", Convert.ToInt32(_ddlHourSelectedValue)));
}
}
public string ddlHourSelectedValue
{
get
{
return _ddlHourSelectedValue;
}
set
{
_ddlHourSelectedValue = value;
}
}
param[6] = new SqlParameter("#Timeslot", ddlHourSelectedValue);
The field in your view is called "ddl_Hour" However is there a variable in your Model with the same name? Otherwise the MVC framework will not automatically populate the value in the model.
Two ways you could go about this.
1
In your controller methods that accepts a post, you can add the parameter: FormCollection fc to the method. This key value pair collection will allow you to fetch results from fields in the post data like so:
string selectedValue = fc["ddl_Hour"];
2
Or you can modify your model to include a variable with the same name as the drop down list so that it is automatically populated for you.
public string ddl_Hour { get; set; }
You should then be able to access the result of the drop down list selection on post from that variable.

MVC3 with EF 4.1 and EntityState.Modified

Updating an object with MVC3
I have a model that I can modify, please see the sample below:
[HttpPost]
public ActionResult Edit(Company c)
{
if (ModelState.IsValid)
{
db.Entry(c).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(c);
}
The model has other fields that are not showing in the view and cannot be modified by the user, but when I click the submit button the fields that were not showing in the view got set to null.
Can I somehow let EF know not to modify certain fields? Thanks.
Generally it is better not to bind to the entity object directly, rather create an edit model and bind to that.
After all.. whats to stop someone posting back values you don't want changed with this approach?
The main problem here is the fact that mvc model binding changes the properties in the model before its in a context therefore the entity framework doesn't know which values have changed (and hence which should be updated)
You've mitigated that slightly with db.Entry(c).State = EntityState.Modified; but that tells the entity framework that the whole record has been updated.
I would normally do the following:
Bind to a model specifically for this controller first
Create an instance of the entity class you want to update, set the Id accordingly and attach it to the context
Update the properties on the entity to be the same as the model you binded to (object is attached and therefore entity framework is tracking which columns are being changed now)
SaveChanges
Step 3 is a bit tedious therefore consider using a tool like automapper to make things easier
Edit:
[HttpPost]
public ActionResult Edit(Company c)
{
if (ModelState.IsValid)
{
Company dbCompayObjct = new Company { companyId = c.companyId };
db.Company.Attach(dbCompayObjct);
dbCompanyObjct.CompanyName = c.CompanyName;
dbCompanyObjct.City = c.City;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(c);
}
You are apparently overwriting your existing record with an incomplete record. When you use the method above, it will completely replace the existing one.
You either need to fill in all the fields you don't want to replace with the existing values, or you need to get the existing record and modify the fields you want to modify, then save it.
Reflection is not always evil, sometimes it's your friend:
public ActionResult Edit(Company c)
{
if (ModelState.IsValid)
{
Company UpdateC = db.Company.find(c.CompanyID);
foreach (var property in typeof(Company).GetProperties())
{
var propval = property.GetValue(c);
if (propval != null)
{
property.SetValue(UpdateC, propval);
}
}
db.SaveChanges();
return RedirectToAction("Index");
}
return View(c);
}

Preselection in a DropDownList

I'm just starting with MVC3 and I have the following situation.
My app's initial sign up page among other controls contains a drop down menu. When the user has completed the form then the form details are saved in a session and they move on to the next step. They may also move back to the original step to re-edit, in which case I need to show the drop down menu with the appropriate value preselected.
My code is as follows:
Controller:
public ActionResult Index()
{
var model = new CompanyDetailsModel();
BindDropDownLists(model);
//IF WE HAVE A SESSION THEN PREFILL THE VALUES
if(MySession.Current.IFA!=null)
model = EditIFAProfileService.returnCompanyDetailSession(MySession.Current.IFA);
return View("CreateCompanyDetails", model);
}
I am getting the expected values from the model, so for example the
value model.Salutation is equal to an integer.
So, armed with that value I would expect to be able to set the preselected value of my dropdownlist as follows:
#Html.DropDownListFor(model => model.SalutationValue, Model.SalutationItems,
"Please Select", new { #tabindex = "1" })
If I do set the model value of SalutationValue to an int then I get an error stating that
ViewData item that has the key is of type 'System.Int32' but must be of type 'IEnumerable'.
Any help would be much appreciated.
Thank you.
Don't use any ViewData if you are working with strongly typed views and view models as it would conflict. Simply set the SalutationValue property to some given value. Here's an example:
public ActionResult Index()
{
var model = new CompanyDetailsModel();
model.SalutationItems = ...
if (MySession.Current.IFA != null)
{
model.SalutationValue = MySession.Current.IFA;
}
return View("CreateCompanyDetails", model);
}

How To Not Have ALL Fields On An Edit View But Not Get The 'Overflow while converting to datetime.'

I am somewhat new to MVC 3 so this could be something simple. I have a Compact SQL 4 database. There is a Post object that has a Contents (string), Subject (string), When (DateTime) and Reposted (DateTime nullable) fields. During the Create's Post method, I manually force the When property to be DateTime.Now and it works great.
However, on my Edit View, I do NOT want to show this field or at least not let it be an editable field. When I do NOT put it as an editable field on the Edit View and they change say the Contents and then click Save I get the message:
An overflow occurred while converting to datetime.
During the Edit Postback, I am setting the Reposted field to DateTime.Now so it has to be the When field. When I debug on that postback I see that the "Post" object is only filled in with values of the fields I am displaying on the screen. So I decided to just grab the When field out with a LINQ query directly from the data but when I get to the SaveChanges it fails and says the following:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key
So how can I update an object and let the user only change a few pertinant fields? Seems like the Post object is not getting ALL of the existing values since they are not showing on the screen. How can I fill that object completely?
Edit: Here is the Post method.
[HttpPost]
public ActionResult Edit(Post post) {
if (ModelState.IsValid) {
db.Posts.Attach(post);
int Successes = 0;
int Failures = 0;
this.SendEMail(post, out Successes, out Failures);
post.Successes = Successes;
post.Failures = Failures;
post.Reposted = DateTime.Now;
db.ObjectStateManager.ChangeObjectState(post, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
Include a hidden field in your view for the fields that you do not want to display e.g.
#Html.HiddenFor(model => model.When)

Resources