Rails自动完成 - 自定义行为以在输入之前列出所有项目

时间:2012-05-23 22:13:45

标签: jquery ruby-on-rails-3 jquery-ui jquery-autocomplete

我正在尝试为Rails 3.2中的字段实现具有特殊行为的自动完成功能。我正在使用rails autocomplete gem,我想做的是:

表单中有一个字段,我想要自动完成工作,其中包含qty和配方成分的数量类型。输入的三个不同示例:

100 gramms
2 pices
3.2 kilos

当用户使用列表中的所有可用选项按空格时,我希望该行为具有下拉列表。当用户输入另一个键时,列表当然会过滤该输入。

是否可以针对上述行为自定义rails自动完成功能?

2 个答案:

答案 0 :(得分:0)

更新。我原来的答案误解了这个问题。

Fisrt选项。

您可以修改控制器操作。

# units_controller
def autocomplete
   term = params[:term]
   quantity, unit = term.split(/\s/)
   items = unit ? Unit.where('units.name LIKE ?',"#{unit}%") : []
   json = items.collect do |item| 
     { "id" => item.id.to_s, 
       "label" => item.name, 
       "value" => "#{quantity} #{item.name} "  
     }
   end
   render json: json
end

虽然自动完成行为已经是正确的,但这个解决方案不是最理想的,因为即使在我输入数量时它也会到达服务器(并且没有给出结果)。

完整的解决方案包括修补rails autocompleter驱动程序。 保持自定义控制器操作,只需添加自定义minLength函数 https://github.com/crowdint/rails3-jquery-autocomplete/blob/master/lib/assets/javascripts/autocomplete-rails-uncompressed.js#L63

您将此部分修改为:

   search: function() {
     // custom minLength
     var term = extractLast( this.value );
     var filter = jQuery(this).attr('data-input-filter');
     if (filter != null) { 
        var re = new RegExp(filter,"");
        term = term.replace(re, "$1"); //ignore parts of it
     }
     if ( term.length < 1 ) { //modify to 1
       return false;
     }
   },

现在,如果您将此minlength过滤器添加到字段标记

'data-input-filter' => j("^.*\s+([^\s]+)$")

它将正确忽略用户输入的第一位(在最后一个空格之后),并且只有在到达单位的第一个字符时才会点击服务器。 (这里不太可能逃脱)

这种方法的一个优点是您可以将成分自动完成添加到您的控制器,并使用逗号并通过将此选项添加到自动填充文本字段助手来获取多个成分输入:

"data-delimiter" => ','

然后您可以正确自动完成输入,例如:

1 kilo flour, 2 spoons sugar, 100 gramms yeast.

答案 1 :(得分:0)

还有一个纯粹的js解决方案,因此您可以在控制器中保持简单

# units controller
autocomplete :unit, :name

你需要修改rails3-jquery-autocomplete js driver。

一个关键的是这个。 https://github.com/crowdint/rails3-jquery-autocomplete/blob/master/lib/assets/javascripts/autocomplete-rails-uncompressed.js#L45 您可以在此处自定义用户输入如何与发送到服务器的实际术语相关联。

问题是您还必须确保选择中插入的值包含数量。由于此值取自服务器json响应,如果您不将数量发送到服务器,则必须在提取的js属性中记住它

function extractLast( term ) {
  var last = split( term ).pop().replace(/^\s+/,"");
  var arr = last.split(/\s+/);
  if (arr.length > 1) {  
     var res = arr.pop();
     jQuery(this).attr('data-quantity').val(arr.join(' '));
  }
  return res;
}

并将其插入在线 https://github.com/crowdint/rails3-jquery-autocomplete/blob/master/lib/assets/javascripts/autocomplete-rails-uncompressed.js#L77

terms.push( (jQuery(this).attr('data-quantity')) + ' ' + ui.item.value );

当然,更好的代码会使这依赖于我接受的答案中的输入字段数据属性。

此解决方案也不允许根据数量解析成分或过滤单位,因为只有单位部分会随请求一起发送。