Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET MVC; using EditorTemplates to edit a collection, best way for dynamic field creation

I am new to ASP.NET MVC, so apologies if this is easier than it looks. I've been Googling around, I have a class like so:

public class Search : IAuditable
{
    [Key]
    public int SearchID { get; set; }
    public int UserID { get; set; }

    ...

    public ICollection<SearchTerm> SearchTerms { get; set; }   
}

In the Create.cshtml, I have the following

<div class="editor-label">
    @Html.LabelFor(model => model.Search.SearchTerms)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Search.SearchTerms, "SearchTerm")
    @Html.ValidationMessageFor(model => model.Search.SearchTerms)
</div>

SearchTerm EditorTemplate is a simple form like so:

@model Core.Search.Parameters.SearchTerm

@Html.HiddenFor(n => n.SearchTermID)
<div class="editor-label">
    @Html.LabelFor(n => n.Text, "Term")
</div>
<div class="editor-field">
    @Html.EditorFor(n => n.Text)
    @Html.ValidationMessageFor(n => n.Text)
</div>

It seems to work, I see a single text box on create (when the default model is empty). However, what I want to do is be able to add / remove the SearchTerms with an Add button so the user can add an arbitrary amount of terms to the collection on create. Is this built in somehow? is there a javascript framework that pairs well with this, that will generate the appropriate html names so I don't have to manually do that? Am I even approaching this the right way, given that I am new to MVC?

Thanks!

like image 734
Richthofen Avatar asked May 02 '13 00:05

Richthofen


1 Answers

In this case I preferred to use PartialView.

You should create an ActionResult which return you PartialView for your item. And when you click "ADD" button you should send ajax request to this ActionResult.

public ActionResult GetTermItem()
{
    return PartialView("_SearchTerm", new SearchTerm());
}

Your PartialView should looks like this:

@model Core.Search.Parameters.SearchTerm
@{ ViewContext.FormContext = new FormContext(); }
@using (Html.BeginCollectionItem("SearchTerms"))
{
    <div class="search-term-item">            
       @Html.HiddenFor(n => n.SearchTermID)
       <div class="editor-label">
          @Html.LabelFor(n => n.Text, "Term")
       </div>
       <div class="editor-field">
          @Html.EditorFor(n => n.Text)
          @Html.ValidationMessageFor(n => n.Text)
       </div>

       <a href="javascript:void(0);" class="remove-search-item" title="Remove">Remove</a>
    </div>
}

Your main page:

<div class="editor-label">
    @Html.LabelFor(model => model.Search.SearchTerms)
</div>
<div id="search-terms-container" class="editor-field">
    @if (Model.SearchTerms != null && Model.SearchTerms.Any())
    {
        foreach (var item in Model.SearchTerms)
        {
             @Html.Partial("_SearchTerm", item)
        }
    }
</div>
<a href="javascript:void(0);" id="add-search-item">Add</a>

And your JavaScript (jQuery) part:

$(document).on('click', '#add-search-term', function () {
    $.ajax({
        url: '@Url.Action("GetTermItem")',
        cache: false,
        success: function (data) {
            var cl = $('#search-terms-container');
            cl.append(data);
            var terms = cl.find('.search-term-item');
            terms.last().hide().show('blind');
        }
    });
    return false;
});

$(document).on('click', '.remove-search-term', function () {
    $(this).closest('.search-term-item').hide('blind', function () { $(this).remove(); });
    var cl = $('#search-terms-container');
    var terms= cl.find('.search-term-item');
    return false;
});
like image 74
melvas Avatar answered Sep 23 '22 15:09

melvas