Kendo AutoComplete - 强制用户做出有效选择

Posted

技术标签:

【中文标题】Kendo AutoComplete - 强制用户做出有效选择【英文标题】:Kendo AutoComplete - force users to make valid selection 【发布时间】:2012-11-13 21:35:21 【问题描述】:

我有几个链接到远程数据的 Kendo AutoComplete 字段(有数百种可能性,所以 DropDownList 不是一个选项)。

如何强制用户从显示的列表中进行选择?

我还在检索从数据源返回的附加数据,例如

$("#station").kendoAutoComplete(
    dataSource: stationData,
    minLength: 2,
    dataTextField: 'name',
    select: function(e)
        var dataItem = this.dataItem(e.item.index());
        console.dir(dataItem);
    
);

我正在对dataItem 中的数据进行其他处理,它必须是有效的选择。

谢谢

已解决: 我想我可能把事情复杂化了。答案很简单,贴在下面。

【问题讨论】:

【参考方案1】:
var valid;
$("#staton").kendoAutoComplete(
  minLength: 2,
  dataTextField: "name",
  open: function(e) 
    valid = false;
  ,
  select: function(e)
    valid = true;
  ,
  close: function(e)
    // if no valid selection - clear input
    if (!valid) this.value('');
  ,
  dataSource: datasource
);

【讨论】:

使用这个方法,如果用户没有做出有效的选择,无论他们在 AutoComplete 中输入了什么都会被清除onblur 这是我想要的结果 在我的测试中,如果用户键入的值从服务器返回 0 个元素,则不会触发“关闭”事件。也就是说,我开始输入“1234..”,它不会从服务器获取任何内容,然后退出文本字段,“关闭”事件不会被触发:-( 这不是正确的答案。您应该使用“更改”事件,而不是“关闭”。【参考方案2】:

如果列表未打开,此方法允许用户在自动完成中键入他们喜欢的任何内容。有两个更正可以解决这个问题:

    初始化变量valid为false:

    var 有效 = 假;

    检查更改事件中是否没有有效选择,但关闭时没有:

    ...
    change: function(e) if (!valid) this.value(''); 
    

【讨论】:

同意@Jakobovski,这好多了。如果用户输入错误并且列表关闭,Mat 的解决方案将触发关闭事件并立即清除该字段。此修改仅在真正的模糊事件上清除输入,并让用户搜索列表。 正如我在上面所说的,当用户键入一个没有从服务器返回“命中”的值时,不会触发“关闭”事件。所以这是一个更好的解决方案。德罗尔【参考方案3】:

除了@Rock'n'muse 建议的答案之外,OP 发布的答案绝对是很好的命题,但都错过了一个重要且理想的功能方面。

当利用@Mat 给出的解决方案并实施@Rock'n'muse 的change-vice-close 建议时,如果没有从过滤器中进行选择,输入的值确实会从小部件中清除数据源。这很棒;但是,如果用户输入有效的内容并从过滤列表中选择一个值,然后将光标放在值的末尾并输入现在 使该值无效的内容(不从数据源返回任何有效的选择),输入的值不会从小部件中清除。

如果应该更改之前输入的(和有效的)值,isValid 的值仍然是true。对此的解决方案是在触发过滤事件后立即将isValid 设置为false。当用户更改输入的值时,小部件会尝试过滤数据源以搜索输入的值。触发filter 事件后立即将isValid 设置为false 可确保@Rock'n'muse 的解决方案所建议的change 事件的“干净状态”。

因为我们在触发filtering 事件时将isValid 设置为false,所以我们不需要在open 事件中这样做(因为数据源过滤必须在用户看到之前进行一个选项来选择)。因此,open 事件绑定已从 @Mat 的解决方案中删除。这也意味着在声明 isValid 时初始分配 false 是多余的,但在声明时分配变量总是一个好主意。

以下是来自@Mat 的解决方案以及来自@Rock'n'muse 的建议以及应用了filtering 实现:

var isValid = false;
$("#staton").kendoAutoComplete(
    minLength: 2,
    dataTextField: "name",
    select: function () 
        valid = true;
    ,
    change: function (e) 
        // if no valid selection - clear input
        if (!valid) 
            e.sender.value("");
        
    ,
    filtering: function () 
        valid = false;
    ,
    dataSource: datasource
);

作为附录,使用select 事件绑定来设置和评估@Mat 建议的简单布尔值比在数据上使用jQuery $.each(...)更简单 source 以确保键入的值与 change 事件中的数据源的实际项匹配。这是我在从@Mat(此页面)找到解决方案之前首先想到的解决方案,这就是我对他的解决方案和他的问题投票的理由。

【讨论】:

【参考方案4】:

也许,您可以使用blur 事件进行自己的验证:

$("#station").blur(function() 
    var data = stationData,
        nbData = data.length,
        found = false;

    for(var iData = 0; iData < nbData; iData++) 
         if(this.value === data[iData].yourfieldname) // replace "yourfieldname" by the corresponding one if needed
             found = true;
    
    console.log(found);
);

您可以查看this fiddle。

【讨论】:

谢谢塞缪尔,我想我可以用这样的东西进行探索。但它确实有一个问题,因为 found 在选择时返回 false,然后在模糊时返回 true(不知道为什么)。 我不明白 'found' 是我设置的变量,并且只存在于 blur 事件的范围内...也许您在 select 事件上添加了具有相同变量的测试?如果是这种情况,这是正常的:选择发生在字段自动完成之前... 嗨。我还没有实现任何东西——这只是对你小提琴的评论。在 Chrome 的控制台中,一旦做出选择就会返回 false。当您点击输入字段时返回 True。【参考方案5】:

您很可能需要一些自定义逻辑来在超过两个符号的最小长度后拦截每个击键,并防止选择输入使用户字符串不匹配的字符的选项任何自动完成列表中的项目。

为此,拦截 Kendo 自动完成的更改事件,并将用户的当前输入值与过滤列表中的项目进行比较。

【讨论】:

【参考方案6】:

希望对你有帮助,

$("#autocomplete_id").val("");

$("#autocomplete").kendoAutoComplete(
    dataSource: datasource,
    minLength: 1,
    dataTextField: "catname",
    dataValueField:"id",
    select: function(e)                 
        var dataItem = this.dataItem(e.item.index());                
        $("#autocomplete_id").val(dataItem.id);
    ,
    dataBound: function(e)
        $("#autocomplete_id").val("");
    
); 

仅供参考,autocomplete_id 是一个隐藏字段,用于存储自动完成的值。 - 有时,我们希望有 dataValueField 而不是 dataTextField。因此,它达到了它的目的。

在此您可以从元素 autocomplete_id 获取自动完成“id”的值 - 这是来自服务器端的 dataValueField。

在数据绑定中,它的值设置为空,在选择时,它被分配了“id”值。

【讨论】:

这并不能真正回答问题——它仍然允许用户在自动完成中输入他们喜欢的任何内容,并且不会强制他们选择有效的选项。【参考方案7】:

虽然accepted answer 有效,但它不是最佳解决方案。

如果用户在 kendo AutoComplete 小部件触发 open 事件之前输入值,则提供的解决方案没有考虑到。结果,输入的值不是强制的,因此输入/选择无效。

我的方法假设应用程序在 MVC 中运行,并且数组在 ViewData 中传递。但这可以根据您的环境进行更改。

我的做法:

var validSelect, isSelected;
$("#staton").kendoAutoComplete(
    minLength: 2,
    filter: "startswith",
    dataTextField: "name",
    filtering: function(e) 
        validSelect = false;
        dataArr = @html.Raw(Json.Encode(ViewData["allStatons"]));
        // for loop within the ViewData array to find for matching ID
        for (var i = 0; i < dataArr .length; i++)
            if (dataArr[i].ID.toString().match("^" + $("#staton").val())) 
                validSelect = true;
                break;
            
        

        // if value entered was not found in array - clear input
        if (!validSelect) $("#staton").val("");
    ,
    select: function(e)
        isSelected = true;
    ,
    close: function(e)
        // if selection is invalid or not selected from the list - clear input
        if (!validSelect || !isSelected) $("#staton").val("");
    ,
    dataSource: datasource
);

如您所见,这种方法需要加载来自服务器端的数组,以便它可以在小部件的过滤事件期间匹配。

【讨论】:

【参考方案8】:

我只是使用更改事件在 Telerik 的网站上找到了这个。对我来说,这效果最好。我添加了“值 === ''”检查。这将在用户“清除”选择时捕获。

Here's the link to the full article.

      $("#countries").kendoAutoComplete(
        dataSource: data,
        filter: "startswith",
        placeholder: "Select country...",
        change: function() 
          var value = this.value();
          if (value === '') return;
          var found = false;
          var data = this.dataSource.view();

          for(var idx = 0, length = data.length; idx < length; idx++) 
            if (data[idx] === value) 
              found = true;
              break;
            
          

          if (!found) 
            this.value("");
            alert("Custom values are not allowed");
          
        
      );

【讨论】:

【参考方案9】:

在我的 AutoComplete Change 事件中,我检查选定的项目,如果未选定则清除单元格。

    function myAutoComplete_OnChange(e)
    
        if (this.dataItem())
        
            // Don't use filtered value as display, instead use this value.
            e.sender.element[0].value = this.dataItem().WidgetNumber;
        
        else
        
            var grid = $("#grid").data("kendoGrid");
            grid.dataItems()[grid.select().index()].WidgetKey = null;
            grid.dataItems()[grid.select().index()].WidgetNumber = null;
        
    

【讨论】:

以上是关于Kendo AutoComplete - 强制用户做出有效选择的主要内容,如果未能解决你的问题,请参考以下文章

Kendo Mobile 的 Kendo AutoComplete?

kendo AutoComplete实现多筛选条件

Kendo UI Angular JS 和带有服务的 AutoComplete

Kendo UI AutoComplete 数据源传输只读取一次

强制用户从google maps api autocomplete中选择地址

Angular-Kendo 在更改时自动完成所选值