I have the model (code first) & database (SQL Server) setup with many to many relationship & seeding fine:
A Place can have many tags (eg Restaurant, bar, cafe) - and tags can belong to many places.
Place
[ScaffoldColumn(false)]
public virtual int PlaceID { get; set; }
[Required(ErrorMessage = "Place Name is required")]
[StringLength(100)]
public virtual string Name { get; set; }
[Required]
public virtual string Address {get;set;}
public virtual string ImageLogo {get;set;}
public virtual string ImageBackground {get;set;}
Tag
public virtual int TagID { get; set; }
[Required]
public virtual string Name { get; set; }
[Required]
public virtual string NamePlural { get; set; }
public virtual ICollection<Place> Places { get; set; }
EF Migrations has generated a junction table with TagID & PlaceID and I can add Places with multiple tags fine in my Seed method. There are about 50 tags - all seeded.
What I would like to do is have a Create view form - that allows users to select from all the tags - maybe with check boxes (open to alternatives), some async textbox etc? Which are then saved with the model.
This data will be entered by an administrator - speed of entry is most important (doesn't have to be 100% idiot proof).
I also need to be able to edit the place - and have those tags show up appropriately to be removed or others added.
Also the best way to handle deletion of places - delete records in junction table first?
What is best practice in all of the above?
Thanks.
I think the best and simplest way for you is that you have a view for creating Place
and at the bottom of it put a fieldset
to assign tags to it.
For the fieldset, you should mave two partial views: One for create and another for edit. The partial view for creating should be somthing like this:
@model myPrj.Models.PlaceTagInfo
@{
var index = Guid.NewGuid().ToString();
string ln = (string)ViewBag.ListName;
string hn = ln + ".Index";
}
<tr>
<td>
<input type="hidden" name="@hn" value="@index" />
@Html.LabelFor(model => model.TagID)
</td>
<td>
@Html.DropDownList(ln + "[" + index + "].TagID",
new SelectList(new myPrj.Models.DbContext().Tags, "ID", "TagName"))
</td>
<td>
<input type="button" onclick="$(this).parent().parent().remove();"
value="Remove" />
</td>
</tr>
By calling this partial view in the create place view ajaxly, you can render some elements for each tag. Each line of elements contains a label, a DropDownList containing tags, and a remove button to simply remove the created elements.
In the create place view, you have a bare table which will contain those elements you create through the partial view:
<fieldset>
<legend>Place Tags</legend>
@Html.ValidationMessageFor(model => model.Tags)</label>
<table id="tblTags"></table>
<input type="button" id="btnAddTag" value="Add new tag"/>
<img id="imgSpinnerl" src="~/Images/indicator-blue.gif" style="display:none;" />
</fieldset>
and you have the following script to create a line of elements for each tag:
$(document).ready(function () {
$("#btnAddTag").click(function () {
$.ajax({
url: "/Controller/GetPlaceTagRow/Tags",
type: 'GET', dataType: 'json',
success: function (data, textStatus, jqXHR) {
$("#tblTags").append(jqXHR.responseText);
},
error: function (jqXHR, textStatus, errorThrown) {
$("#tblTags").append(jqXHR.responseText);
},
beforeSend: function () { $("#imgSpinnerl").show(); },
complete: function () { $("#imgSpinnerl").hide(); }
});
});
});
The action method GetPlaceTagRow
is like the following:
public PartialViewResult GetPlaceTagRow(string id = "")
{
ViewBag.ListName = id;
return PartialView("_CoursePostPartial");
}
and your done for the create... The whole solution for your question has many codes for views, partial views, controllers, ajax calls and model binding. I tried to just show you the way because I really can't to post all of them in this answer.
Hope that this answer be useful and lead the way for you.