0

I am trying to use one view in which I display current results which has the ability to add a new record. I looked at this post and also this post and pieced together something I think should work but it will not save to the database. Here is my view model:

public class LabIndexViewModel
    {
        public Lab Lab { get; set; }
        public IEnumerable<Lab> Labs { get; set; }
    }

And in my controller I have this in my index:

public ActionResult Index(int patid = 0, Lab lab = null)
        {
            ViewBag.Finalize = PatientSubmitted(patid);
            ViewBag.DispPatientId = patid;
            ViewBag.CheckButtonStatus = ButtonSubmitted(patid);
            var labs = db.Labs.Where(l => l.PatientId == patid && l.Active);
            LabIndexViewModel model = new LabIndexViewModel();
            model.Labs = labs.ToList();
            model.Lab = lab;
            SetViewBagLists();
            return View(model);
        }

Then in my post where it will not save:

[HttpPost]
        public ActionResult Create(LabIndexViewModel labindex)
        {
            ViewBag.DispPatientId = labindex.Lab.PatientId;
            Lab lab = labindex.Lab;

            try
            {
                lab.Active = true;
                db.Labs.Add(lab);
                db.SaveChanges();
                return RedirectToAction("Index", "Lab", new { patid = lab.PatientId });
            }

            catch
            {
                ViewBag.Phase = new SelectList(StatusList(), "Text", "Value");
                ViewBag.Name = new SelectList(db.LabOptions, "Test", "Value", lab.Name);
                return View(lab);
            }
        }

Here is my partial where I submit the data in my view:

@model PamperWeb.Models.LabIndexViewModel

@using (Html.BeginForm("Create", "Lab")) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Lab</legend>

      <tr>
        <td>
            @Html.DropDownList("Name", String.Empty)
            @Html.ValidationMessageFor(model => model.Lab.Name)
        </td>

        <td>
            @Html.EditorFor(model => model.Lab.Value)
            @Html.ValidationMessageFor(model => model.Lab.Value)
        </td>

        <td>
            @Html.EditorFor(model => model.Lab.Given)
            @Html.ValidationMessageFor(model => model.Lab.Given)
        </td>

        <td>
            @Html.EditorFor(model => model.Lab.TimeGiven)
            @Html.ValidationMessageFor(model => model.Lab.TimeGiven)
        </td>

        <td>
            @Html.DropDownList("Phase", String.Empty)
            @Html.ValidationMessageFor(model => model.Lab.Phase)
        </td>

        @Html.HiddenFor(model => model.Lab.PatientId)

        <td>
            <input type="submit" value="Create" />
        </td>
       </tr>
    </fieldset>
}

Anybody have any idea on how to make this work or have a good example?

Community
  • 1
  • 1
Xaxum
  • 3,545
  • 9
  • 46
  • 66
  • 1
    What do you mean when you say that it's not saving? Have you put a breakpoint to test if it's getting into `Create` action? – Andre Calil Jun 04 '13 at 17:14
  • @AndreCalil Yes. It hits the controller post but once it hits db.save(lab) it bombs and hits the catch and redirects to the create get method. – Xaxum Jun 04 '13 at 20:18
  • Nice! And what does the exception say...? – Andre Calil Jun 04 '13 at 20:35
  • He has a tipical ModelBinder issue @AndreCalil! I posted the answer above! – Fals Jun 05 '13 at 03:00
  • 2
    @Fals I'm not sure, the action get the post as expected. I believe it must be a missing required property or something like it. Anyway, it's a little hard to understand, indeed – Andre Calil Jun 05 '13 at 12:28
  • @AndreCalil You are correct. It ended up being a required field issue. When I added the parameters to html.beginform(Create, "Lab") it no longer passed my ?patientid= parameter in the url. So I ended up adding it to the model before I passed it to the view so my hidden parameter would have a value. I was not sure how to display the error in the catch so I stumbled upon it in the view. – Xaxum Jun 05 '13 at 13:38

2 Answers2

1

I didn't realy understand all the question, but I saw something wrong there:

1) Yours PartialView must post a Lab, so make It strongly typed for Lab, because HTML Helpers will generate HTML that the default ModelBinder cannot process to build the model back in the server using LabIndexViewModel:

@model PamperWeb.Models.Lab

@using (Html.BeginForm("Create", "Lab")) {
  @Html.ValidationSummary(true)
  <fieldset>
    <legend>Lab</legend>
    <tr>
      <td>
        @Html.DropDownList("Name", String.Empty)
        @Html.ValidationMessageFor(model => model.Name)
      </td>

    <td>
        @Html.EditorFor(model => model.Value)
        @Html.ValidationMessageFor(model => model.Value)
    </td>

    <td>
        @Html.EditorFor(model => model.Given)
        @Html.ValidationMessageFor(model => model.Given)
    </td>
    <td>
        @Html.EditorFor(model => model.TimeGiven)
        @Html.ValidationMessageFor(model => model.TimeGiven)
    </td>

    <td>
        @Html.DropDownList("Phase", String.Empty)
        @Html.ValidationMessageFor(model => model.Phase)
    </td>
        @Html.HiddenFor(model => model.PatientId)
    <td>
        <input type="submit" value="Create" />
    </td>
  </tr>
</fieldset>
}

2) Change the controller Action Create to receive as parameter the posted Lab:

[HttpPost]
public ActionResult Create(Lab lab)
{
  ViewBag.DispPatientId = Lab.PatientId;

  try
  {
    lab.Active = true;
    db.Labs.Add(lab);
    db.SaveChanges();
    return RedirectToAction("Index", "Lab", new { patid = lab.PatientId });
  }
  catch
  {
    ViewBag.Phase = new SelectList(StatusList(), "Text", "Value");
    ViewBag.Name = new SelectList(db.LabOptions, "Test", "Value", lab.Name);
    return View(lab);
  }
}

3) Use the ViewModel created to display the labs! Thats the ViewModel master purpose, display complex types in the view! Any other opperation requires creation of a custom ModelBinder to interate throught the request and build the model back in the server.

Hopes this help you! I really got this from the question!

Fals
  • 6,813
  • 4
  • 23
  • 43
  • Thanks for the help. I ended up using part of this to make things a little more straight forward. – Xaxum Jun 05 '13 at 13:39
  • No problem! Hopes this help you! And if this solve the problem, don't forget to marget as anwsear! – Fals Jun 05 '13 at 13:54
  • 1
    The actual answer was what @AndreCalil suggested in the comments above. I was missing a required field because I added the paramters. See more explanation for my posted result. – Xaxum Jun 05 '13 at 14:01
0

With the help of the comments I was able to figure out the issue. When I added the parameters to the html.beginform it no longer sent my url parameters with the patientid. Not sure why? My normal create view had this so my hidden parameter picked up the value. I ended up setting the value in my controller so the hidden parameter in the form was able to pick it up. Here is what my get index is now which resolved the issue:

public ActionResult Index(int patid = 0, Lab lab = null)
        {
            ViewBag.Finalize = PatientSubmitted(patid);
            ViewBag.DispPatientId = patid;
            ViewBag.CheckButtonStatus = ButtonSubmitted(patid);
            var labs = db.Labs.Where(l => l.PatientId == patid && l.Active);
            LabIndexViewModel model = new LabIndexViewModel();
            if (lab == null)
                lab = new Lab();
            lab.PatientId = patid;
            model.Labs = labs.ToList();
            model.Lab = lab;
            SetViewBagLists();
            return View(model);
        }

I also found this post helpful in that I found out I can specify a model to send to a partial.

Community
  • 1
  • 1
Xaxum
  • 3,545
  • 9
  • 46
  • 66