我正在尝试为 Rails 3.2 中的字段实现具有特殊行为的自动完成功能。我正在使用 rails 自动完成 gem,我想要做的是:
表单中有一个字段,我希望自动完成在其中包含配方成分的数量和数量类型。输入的三个不同示例:
100 gramms
2 pices
3.2 kilos
我希望当用户使用列表中的所有可用选项按空格键时,该行为具有下拉菜单。当用户输入另一个键时,列表当然会过滤该输入。
是否可以为上述行为自定义 rails 自动完成功能?
我正在尝试为 Rails 3.2 中的字段实现具有特殊行为的自动完成功能。我正在使用 rails 自动完成 gem,我想要做的是:
表单中有一个字段,我希望自动完成在其中包含配方成分的数量和数量类型。输入的三个不同示例:
100 gramms
2 pices
3.2 kilos
我希望当用户使用列表中的所有可用选项按空格键时,该行为具有下拉菜单。当用户输入另一个键时,列表当然会过滤该输入。
是否可以为上述行为自定义 rails 自动完成功能?
更新。我原来的回答误解了这个问题。
第一个选项。
您修改控制器操作。
# 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 驱动程序。保留 abave 自定义控制器操作,只需放置自定义 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.
还有一个纯js的解决方案,所以你可以在你的控制器中保持简单
# units controller
autocomplete :unit, :name
并且您需要修改 rails3-jquery-autocomplete js 驱动程序。
一条关键线是这一点。 https://github.com/crowdint/rails3-jquery-autocomplete/blob/master/lib/assets/javascripts/autocomplete-rails-uncompressed.js#L45 您可以在此处自定义用户输入与发送到服务器的实际术语的关系完成。
问题是您还必须确保在选择中插入的值包含数量。由于该值取自服务器 json 响应,因此如果您不将数量发送到服务器,则必须在 extract 的 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;
}
terms.push( (jQuery(this).attr('data-quantity')) + ' ' + ui.item.value );
当然,更好的代码会使这取决于我接受的答案中的输入字段数据属性。
该解决方案也不允许基于数量解析成分或过滤单元,因为只有单元部分是随请求发送的。