使用Html.BeginCollectionItem的MVC AutoComplete EditorFor [英] MVC AutoComplete EditorFor while using Html.BeginCollectionItem

查看:151
本文介绍了使用Html.BeginCollectionItem的MVC AutoComplete EditorFor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 EditorTemplate 创建自动完成文本框。我面临的问题是通过使用 Html.BeginCollectionItem()扩展解决方案( https://www.nuget.org/packages/BeginCollectionItem/ ), EditorFor() TextBoxFor()方法动态设置,这打破了我的JavaScript。接下来,我不完全知道这是否是可能的(如果是这样,如何,下面你会发现我有多远)。



主要view我有一个循环来为集合中的每个项目生成一个局部视图

  for(int i = 0; i< Model.VoedingCollection.Count; i ++)
{
@ Html.EditorFor(x => x.VoedingCollection [i],CreateVoedingTemplate)
}

部分视图 CreateVoedingTemplate.cshtml 使用 Html。 BeginCollectionItem()方法

  @using(Html.BeginCollectionItem(VoedingCollection))
{
string uniqueId = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[','_')。Replace(']','_')。ToString();
字符串searchId =Search_;
string standaardVoedingId =StandaardVoeding_;
foreach(KeyValuePair< ViewData中的字符串,对象>项目)
{
if(item.Key ==Count)
{
searchId = searchId + item .Value.ToString();
standaardVoedingId = standaardVoedingId + item.Value.ToString();
}
}

< div class =form-horizo​​ntal>
< div class =form-groupid = @ standaardVoedingId>
@ Html.LabelFor(model => model.fk_standaardVoedingId,Voeding naam,htmlAttributes:new {@class =control-label col-md-2})
< div class = COL-MD-10 >
@ Html.HiddenFor(model => model.fk_standaardVoedingId)
< input type =textid ='@ searchId'placeholder =搜索产品/>
< / div>
< / div>
< / div>

< script type =text / javascript>
var id ='@uniqueId'+'_fk_standaardVoedingId'.toString();
var search ='@ searchId'.toString();
$ b var url ='@ Url.RouteUrl(DefaultApi,new {httproute =,controller =AgendaApi})';
$ b $(document.getElementById(search))。autocomplete({
source:function(request,response){
$ .ajax({
url:url ,
data:{query:request.term},
dataType:'json',
类型:'GET',
成功:函数(数据){
响应($。map(data,function(item){
return {
label:item.standaardVoedingNaam,
value:item.standaardVoedingId
}
})) ;
}
})
},
select:function(event,ui){
$(document.getElementById(search)).val(ui.item .label);
//$('#id').val(ui.item.value);
document.getElementById (id).value = ui.item.value;
返回false;
},
minLength:1
});
< / script>
}

< link href =〜/ Content / SearchBox / jquery-ui.css =stylesheet/>
< script src =〜/ Scripts / SearchBox / jquery-1.9.1.js>< / script>
< script src =〜/ Scripts / SearchBox / jquery-ui.js>< / script>

在上面的脚本中,我试图创建一个函数,用户可以输入一个 standaardVoeding 项目,然后得到结果,其中,在用户选择 standaardVoeding 项目后, standaardVoedingId 属性被设置。然后,在提交整个表单之后,控制器会收到 standaardVoedingId (以及所有其他信息)

所以我猜Javascript不知何故无法处理Razor视图 @ 代码,并且在其旁边, Html.BeginCollectionItem 因为您无法在运行时通过代码设置其文本框的值。接下来,我尝试了 alert(document.getElementById(* html.begincollectionitemId *)),它发现这些字段正确。但显然所有其他方法不起作用?



是否有更好的解决方案来实现它?

BeginCollectionItem()方法改变 id name 内置助手生成的html属性,在你的情况下,隐藏的输入,而不是

 < input ... name =fk_standaardVoedingId.... /> 

它会生成

 < input ... name =VoedingCollection [xxxx] .fk_standaardVoedingId.... /> 

其中 xxxx Guid



尽管可以使用javascript来提取 Guid 值从文本框(假设正确地生成了 @ Html.TextBoxFor())并且构建相关隐藏输入的id用作选择器,更容易使用类名和相对选择器。



您还需要从部分中删除脚本和css,并将其放在主视图(或其布局)中。除了内嵌脚本之外,您还需要为集合中的每个项目复制它。



您的部分需要是

  @using(Html.BeginCollectionItem(VoedingCollection))
{
< div class =form-horizo​​ntal>
< 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> //添加类名
@ Html.HiddenFor(model => model.fk_standaardVoedingId)
< input type =textclass =searchplaceholder =搜索产品/>
< / div>
< / div>
< / div>

$ / code>

请注意文本框及其容器的类名,它也包含隐藏的输入。然后在主视图中,脚本将是 $ b

 < script type =text / javascript > 
var url ='@ Url.RouteUrl(DefaultApi,new {httproute =,controller =AgendaApi})';
//将脚本附加到所有文本框$​​ b $ b $('。search')。autocomplete({
source:function(request,response){
$ .ajax({
url:url,
data:{query:request.term},
dataType:'json',
类型:'GET',
成功:函数){
response($。map(data,function(item){
return {
label:item.standaardVoedingNaam,
value:item.standaardVoedingNaam,// this need to成为名称
id:item.standaardVoedingId //为id
}
}));
}
})
},$添加属性b $ b select:function(event,ui){
//获取关联的隐藏输入
var input = $(this).closest('。item ).find(输入[类型= 隐藏]);
//设置id属性的值
input.val(ui.item.id);
},
minLength:1
});
< / script>






根据您的意见,您不会动态添加或删除视图中的项目,那么在额外开销或使用 BeginCollectionItem()方法中没有任何意义。将您的部分名称更改为 standaardvoeding.cshtml (假设这是该类的名称)并将其移至 / Views / Shared / EditorTemplates 文件夹。

然后在主视图中,用

替换循环中的 >

  @ Html.EditorFor(m => m.VoedingCollection)

这将为集合中的每个项目生成正确的html。最后,从模板中删除 BeginCollectionItem()方法,以便它只是它的
$ b

 < div class =form-horizo​​ntal> 
< 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> //添加类名
@ Html.HiddenFor(m => m.fk_standaardVoedingId)
< input type =textclass =searchplaceholder =搜索产品/>
< / div>
< / div>
< / div>


I am trying to create an AutoComplete textbox, while using an EditorTemplate. The problem I am facing is that by using the Html.BeginCollectionItem() extension solution (https://www.nuget.org/packages/BeginCollectionItem/), the Id's of the EditorFor() and TextBoxFor() methods get set dynamically and this breaks my javascript. Next to that, I do not exactly know if this is even possible (and if so, how. Below you will find how far I have come).

In the main view I have a loop to generate a partial view for each item in a collection

for (int i = 0; i < Model.VoedingCollection.Count; i++)
{
    @Html.EditorFor(x => x.VoedingCollection[i], "CreateVoedingTemplate")
}

The partial view CreateVoedingTemplate.cshtml uses the Html.BeginCollectionItem() method

@using (Html.BeginCollectionItem("VoedingCollection"))
{
    string uniqueId = ViewData.TemplateInfo.HtmlFieldPrefix.Replace('[', '_').Replace(']', '_').ToString();
    string searchId = "Search_";
    string standaardVoedingId = "StandaardVoeding_";
    foreach (KeyValuePair<string, object> item in ViewData)
    {
        if (item.Key == "Count")
        {
            searchId = searchId + item.Value.ToString();
            standaardVoedingId = standaardVoedingId + item.Value.ToString();
        }
    }

    <div class="form-horizontal">   
       <div class="form-group" id=@standaardVoedingId>
            @Html.LabelFor(model => model.fk_standaardVoedingId, "Voeding naam", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.HiddenFor(model => model.fk_standaardVoedingId)
                    <input type="text" id='@searchId' placeholder="Search for a product"/>
                </div>
       </div>
    </div>

    <script type="text/javascript">
        var id = '@uniqueId' + '_fk_standaardVoedingId'.toString();
        var search = '@searchId'.toString();

        var url = '@Url.RouteUrl("DefaultApi", new { httproute = "", controller = "AgendaApi" })';

        $(document.getElementById(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.standaardVoedingId
                            }
                        }));
                    }
                })
            },
            select: function (event, ui) {
                $(document.getElementById(search)).val(ui.item.label);
                //$('#id').val(ui.item.value);
                document.getElementById(id).value = ui.item.value;
                return false;
            },
            minLength: 1
        });
    </script>
}

<link href="~/Content/SearchBox/jquery-ui.css" rel="stylesheet" />
<script src="~/Scripts/SearchBox/jquery-1.9.1.js"></script>
<script src="~/Scripts/SearchBox/jquery-ui.js"></script>

In the script above, I am trying to make a function where the user can type in the name of a standaardVoeding item and then get results, where, after the user selects a standaardVoeding item, the standaardVoedingId property gets set. Then, after submitting the whole form, the controller receives the standaardVoedingId (with all the other info as well)

So I guess Javascript somehow cannot handle the Razor View @ code and, next to that, Html.BeginCollectionItem does something fishy because you cannot set the value of its textboxes via code during runtime. Next to that, I have tried doing alert(document.getElementById(*html.begincollectionitemId*)) and it finds the fields fine. But apparently all other methods do not work?

Is there perhaps a better solution to getting this to work?

解决方案

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>

这篇关于使用Html.BeginCollectionItem的MVC AutoComplete EditorFor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆