I am trying to create an AutoComplete textbox, while using an EditorTemplate
. The problem I am facing is that by using the Html.BeginCollectionItem()
The BeginCollectionItem()
method alters the id
and name
attributes of the html generated by the inbuilt helpers, in your case, for the hidden input, instead of
<input ... name="fk_standaardVoedingId" .... />
it will generate
<input ... name="VoedingCollection[xxxx].fk_standaardVoedingId" .... />
where xxxx
is a Guid
.
While it would be possible to use javascript to extract the Guid
value from the textbox (assuming that was generated correctly usind @Html.TextBoxFor()
) and build the id of the associated hidden input to use as a selector, it is far easier to use class names and relative selectors.
You also need to remove your scripts and css from the partial and put that in the main view (or its layout). Apart from the inline scripts, your duplicating it for each item in your collection.
Your partial needs to be
@using (Html.BeginCollectionItem("VoedingCollection"))
{
<div class="form-horizontal">
<div class="form-group">
@Html.LabelFor(model => model.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10 item"> // add class name
@Html.HiddenFor(model => model.fk_standaardVoedingId)
<input type="text" class="search" placeholder="Search for a product"/>
</div>
</div>
</div>
}
Note the class name for the textbox and its container which also includes the hidden input. Then in the main view, the script will be
<script type="text/javascript">
var url = '@Url.RouteUrl("DefaultApi", new { httproute = "", controller = "AgendaApi" })';
// Attach the script to all textboxes
$('.search').autocomplete({
source: function (request, response) {
$.ajax({
url: url,
data: { query: request.term },
dataType: 'json',
type: 'GET',
success: function (data) {
response($.map(data, function (item) {
return {
label: item.standaardVoedingNaam,
value: item.standaardVoedingNaam, // this needs to be the name
id: item.standaardVoedingId // add property for the id
}
}));
}
})
},
select: function (event, ui) {
// Get the associated hidden input
var input = $(this).closest('.item').find('input[type="hidden"]');
// Set the value of the id property
input.val(ui.item.id);
},
minLength: 1
});
</script>
Based on your comments that your are not dynamically adding or removing items in the view, then there is no point in the extra overhead or using the BeginCollectionItem()
method. Change the name of your partial to standaardvoeding.cshtml
(assuming that's the name of the class) and move it to the /Views/Shared/EditorTemplates
folder.
Then in the main view, replace your for
loop with
@Html.EditorFor(m => m.VoedingCollection)
which will generate the correct html for each item in the collection. Finally remove the BeginCollectionItem()
method from the template so that its just
<div class="form-horizontal">
<div class="form-group">
@Html.LabelFor(m => m.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10 item"> // add class name
@Html.HiddenFor(m => m.fk_standaardVoedingId)
<input type="text" class="search" placeholder="Search for a product"/>
</div>
</div>
</div>