Using the Entity Data Framework, I have a model defined called Client which simply contains an id and a name. I then have an association with another model called Appointment containing an id and a date.
For the form, I wish to allow users to create a new client and on the same form, add appointments (before the client is created). I have it partially working (adding one appointment).
In the controller:
[HttpPost]
public ActionResult Create(Client client)
{
var appointment = new Appointment();
UpdateModel(appointment);
client.Appointments.Add(appointment);
db.AddToClients(client);
db.SaveChanges();
return RedirectToAction("Index");
}
In the view:
<div class="editor-label">
<%= Html.LabelFor(model => model.Name) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Name) %>
<%= Html.ValidationMessageFor(model => model.Name) %>
</div>
<% Html.RenderPartial("Appointment", new Appointment()); %>
'Partial' view:
<div class="editor-label">
<%= Html.LabelFor(model => model.AppointmentDate) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.AppointmentDate) %>
<%= Html.ValidationMessageFor(model => model.AppointmentDate) %>
</div>
However, this is not ideal for several reasons:
- Only one appointment can be added
- Issues will occur if there are any name conflicts (e.g. a field called
Commentsin bothClientandAppointmenttable), since no prefixing is done on the field names, which also prevents more than one appointment being added as well
What can I do to allow multiple appointments to be added, i.e. using a button to render a partial view (using AJAX probably) on the page when 'new appointment' is clicked to allow as many appointments as possible? I would also like this to be a shared view that can be used for both creating and editing records as well as adding/deleting appointments in the same form.
Update
Some progress, using a ViewModel:
public class ClientViewModel
{
public Client Client { get; set; }
public List<Appointment> Appointments { get; set; }
}
Controller:
public ActionResult Create()
{
Client c = new Client();
List<Appointment> appointments = new List<Appointment>();
appointments.Add(new Appointment() { AppointmentDate = DateTime.Now });
appointments.Add(new Appointment() { AppointmentDate = DateTime.Now.AddMonths(1) });
var model = new ClientViewModel
{
Client = c,
Appointments = appointments
};
return View(model);
}
[HttpPost]
public ActionResult Create(ClientViewModel m)
{
try
{
foreach (var appointment in m.Appointments)
{
m.Client.Appointments.Add(appointment);
}
db.AddToClients(m.Client);
db.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
View (for appointments, does not work with a foreach loop, as each of the appointments are prefixed with Appointment_ rather than Appointment[0]_):
<%= Html.EditorFor(model => Model.Client) %>
<% for (int i = 0; i < Model.Appointments.Count(); i++) { %>
<%= Html.EditorFor(model => Model.Appointments[i])%>
<% } %>
This is fine for creating appointments for a new client, but what about editing them, as well as adding new appointments without posting back the form? For adding, a link that shows a new appointment form under the existing one, with another link to delete (hide from view and set a hidden field value).
Update 2
Got it working, for adding appointments when first creating a client. However, I am not sure how to update existing appointments (without just deleting them all and adding again).
In controller:
[HttpPost]
public PartialViewResult AddAppointment(Appointment appointment, int index)
{
List<Appointment> appointments = new List<Appointment>();
for (int i = 0; i < index; i++)
{
appointments.Add(null);
}
appointments.Add(new Appointment() { AppointmentDate = DateTime.Now });
ViewData["index"] = index;
var model = new ClientViewModel
{
Appointments = appointments
};
return PartialView("Appointment", model);
}
View:
<%= Html.EditorFor(model => Model.Client) %>
<div id="appointments">
<% for (int i = 0; i < Model.Appointments.Count(); i++) { %>
<%= Html.EditorFor(model => Model.Appointments[i]) %>
<% } %>
</div>
<a href="javascript:;" id="addappointment">Add Appointment</a>
<script type="text/javascript">
var appIndex = <%= Model.Appointments.Count() %>;
$("#addappointment").click(function () {
$.post(
"/Client/AddAppointment",
{"index" : appIndex},
function (result) {
$("#appointments").append(result);
// increase index by 1
appIndex++;
}
);
});