我对客户端开发很新。虽然可能有一些解决方案已经可用。让我试着描述我的问题场景。我有一个JSF page
(表单),其中存在不同的下降(选择框)。他们可以是国籍,语言或宗教。当我们输入代码时,它会选择国籍或语言。在这基本上是server hit goes(partial ajax request)
。我的大四学生建议我完全开发这个auto-complete
功能的客户端。他们不希望任何服务器受到攻击。
他们基本上想要的是,当我输入一些值时,它会从客户端加载建议列表,它不应该转到服务器。它应该比update the jsf component
相应吗?我该如何处理这个问题?任何建议都有帮助。
当前项目基础有此代码 - 自定义组件
public class VisionSelectOneMenuRenderer extends InputRenderer {
@Override
public void decode(FacesContext context, UIComponent component) {
VisionSelectOneMenu menu = (VisionSelectOneMenu) component;
if (menu.isDisabled() || menu.isReadonly()) {
return;
}
decodeBehaviors(context, menu);
String clientId = menu.getClientId(context);
String value = context.getExternalContext().getRequestParameterMap().get(clientId + "_selectBox");
if (value != null) {
menu.setSubmittedValue(value);
}
}
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
VisionSelectOneMenu menu = (VisionSelectOneMenu) component;
encodeMarkup(context, menu);
encodeScript(context, menu);
}
protected void encodeMarkup(FacesContext context, VisionSelectOneMenu menu) throws IOException {
List<SelectItem> selectItems = getSelectItems(context, menu);
String clientId = menu.getClientId(context);
boolean disabled = menu.isDisabled();
Class type = getValueType(context, menu);
String styleclass = menu.getStyleClass();
styleclass = styleclass == null ? VisionSelectOneMenu.STYLE_CLASS : VisionSelectOneMenu.STYLE_CLASS + " " + styleclass;
styleclass = disabled ? styleclass + " ui-state-disabled" : styleclass;
styleclass = "sfield";
/* writer.startElement("div", menu);
writer.writeAttribute("id", clientId, "id");
writer.writeAttribute("class", styleclass, "styleclass");
if(style != null)
writer.writeAttribute("style", style, "style"); */
encodeInput(context, menu, clientId, selectItems, type);
//encodeLabel(context, menu, selectItems, type);
//encodeMenuIcon(context, menu);
// encodePanel(context, menu, selectItems, type);
// writer.endElement("div");
}
protected void encodeInput(FacesContext context, VisionSelectOneMenu menu, String clientId, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
String inputId = clientId + "_selectBox";
writer.startElement("div", menu);
writer.writeAttribute("class", "sfield", null);
writer.startElement("select", menu);
writer.writeAttribute("id", inputId, "id");
writer.writeAttribute("tabindex", "-1", null);
writer.writeAttribute("name", inputId, null);
//writer.writeAttribute("class", "searchableSelectLookupSelect", null);
if (menu.getOnchange() != null) {
writer.writeAttribute("onchange", menu.getOnchange(), null);
}
if (menu.isDisabled()) {
writer.writeAttribute("disabled", "disabled", null);
}
encodeSelectItems(context, menu, selectItems, type);
writer.endElement("select");
writer.startElement("input", null);
writer.writeAttribute("id", clientId, null);
//writer.writeAttribute("tabindex", "-1", null);
writer.writeAttribute("name", clientId, null);
writer.writeAttribute("type", "text", null);
writer.writeAttribute("class", "searchableSelectLookupText excludeClear", null);
if (menu.isDisabled()) {
writer.writeAttribute("disabled", "disabled", null);
}
writer.endElement("input");
writer.endElement("div");
}
protected void encodeLabel(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
String label = getSelectedLabel(context, menu, selectItems, type);
writer.startElement("a", null);
writer.writeAttribute("href", "#", null);
writer.writeAttribute("class", VisionSelectOneMenu.LABEL_CONTAINER_CLASS, null);
if (menu.getTabindex() != null) {
writer.writeAttribute("tabindex", menu.getTabindex(), null);
}
writer.startElement("label", null);
writer.writeAttribute("class", VisionSelectOneMenu.LABEL_CLASS, null);
if (label.equals(" ")) {
writer.write(label);
}
else {
writer.writeText(label, null);
}
writer.endElement("label");
writer.endElement("a");
}
protected void encodeMenuIcon(FacesContext context, VisionSelectOneMenu menu) throws IOException {
ResponseWriter writer = context.getResponseWriter();
writer.startElement("div", menu);
//writer.writeAttribute("class", VisionSelectOneMenu.TRIGGER_CLASS, null);
writer.startElement("span", menu);
//writer.writeAttribute("class", "ui-icon ui-icon-triangle-1-s", null);
writer.endElement("span");
writer.endElement("div");
}
protected void encodePanel(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
boolean customContent = menu.getVar() != null;
int height = calculatePanelHeight(menu, selectItems.size());
writer.startElement("div", null);
writer.writeAttribute("id", menu.getClientId(context) + "_panel", null);
writer.writeAttribute("class", VisionSelectOneMenu.PANEL_CLASS, null);
if (height != -1) {
writer.writeAttribute("style", "height:" + height + "px", null);
}
if (customContent) {
writer.startElement("table", menu);
writer.writeAttribute("class", VisionSelectOneMenu.TABLE_CLASS, null);
writer.startElement("tbody", menu);
encodeOptionsAsTable(context, menu, selectItems, type);
writer.endElement("tbody");
writer.endElement("table");
}
else {
writer.startElement("ul", menu);
writer.writeAttribute("class", VisionSelectOneMenu.LIST_CLASS, null);
encodeOptionsAsList(context, menu, selectItems, type);
writer.endElement("ul");
}
writer.endElement("div");
}
protected void encodeOptionsAsTable(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
String var = menu.getVar();
List<Column> columns = menu.getColums();
Object value = menu.getValue();
for (SelectItem selectItem : selectItems) {
Object itemValue = selectItem.getValue();
Object coercedItemValue = null;
if (itemValue != null && !itemValue.equals("")) {
coercedItemValue = context.getApplication().getExpressionFactory().coerceToType(itemValue, type);
}
boolean selected = (value != null && value.equals(coercedItemValue));
context.getExternalContext().getRequestMap().put(var, selectItem.getValue());
String rowStyleClass = selected ? VisionSelectOneMenu.ROW_CLASS + " ui-state-active" : VisionSelectOneMenu.ROW_CLASS;
writer.startElement("tr", null);
writer.writeAttribute("class", rowStyleClass, null);
if (itemValue instanceof String) {
writer.startElement("td", null);
writer.writeAttribute("colspan", columns.size(), null);
writer.write(selectItem.getLabel());
writer.endElement("td");
}
else {
for (Column column : columns) {
writer.startElement("td", null);
column.encodeAll(context);
writer.endElement("td");
}
}
writer.endElement("tr");
}
context.getExternalContext().getRequestMap().put(var, null);
}
protected void encodeOptionsAsList(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
Object value = menu.getValue();
for (int i = 0; i < selectItems.size(); i++) {
SelectItem selectItem = selectItems.get(i);
Object itemValue = selectItem.getValue();
String itemLabel = selectItem.getLabel();
Object coercedItemValue = null;
itemLabel = isValueBlank(itemLabel) ? " " : itemLabel;
if (itemValue != null && !itemValue.equals("")) {
coercedItemValue = context.getApplication().getExpressionFactory().coerceToType(itemValue, type);
}
boolean selected = (i == 0 && value == null) || (value != null && value.equals(coercedItemValue));
String itemStyleClass = selected ? VisionSelectOneMenu.ITEM_CLASS + " ui-state-active" : VisionSelectOneMenu.ITEM_CLASS;
writer.startElement("li", null);
writer.writeAttribute("class", itemStyleClass, null);
if (itemLabel.equals(" ")) {
writer.write(itemLabel);
}
else {
writer.writeText(itemLabel, null);
}
writer.endElement("li");
}
}
protected void encodeScript(FacesContext context, VisionSelectOneMenu menu) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String clientId = menu.getClientId(context);
writer.startElement("script", null);
writer.writeAttribute("type", "text/javascript", null);
//writer.write("var selectedText = '';");
// TEXT box script
//writer.write("jQuery(document).ready(function(){$('#"+clientId+"').val($('#"+clientId+"_selectBox option:selected').text());});" +
writer.write(
"jQuery(document).ready(function(){" +
//" if($('#"+clientId+"_selectBox').is(':disabled')){ $('#"+clientId+"').attr('disabled','disabled') }" +
"$('#" + clientId + "_selectBox').focus(function(){" +
//"if(!$('#"+clientId+"_selectBox').is(':hover')){"+
// " $('#"+clientId+"').val(''); $('#"+clientId+"').focus();} "+
"});" +
"$('#" + clientId + "').val($('#" + clientId + "_selectBox option:selected').text());" +
/*"$('#"+clientId+"_selectBox option').each(function(){" +
//"var idvalue = $(this).text().split('$')[0];" +
"var level = $(this).text().split(' [')[0];" +
"var levelCode = $(this).text().split(' [')[1];" +
"var desc = level.concat('^');" +
"if(null != levelCode && typeof(levelCode)!='undefined' && levelCode.length > 0) {" +
"var subStr = levelCode.substring(0,3);" +
"desc = desc.concat(levelCode.substring(0,levelCode.length-1));" +
"$(this).attr('description',desc);" +
"}"+
//"$(this).attr('description',$(this).text());" +
//"$(this).text(idvalue);" +
"$('#"+clientId+"').val($('#"+clientId+"_selectBox option:selected').text());" +
"}" +
")});" +*/
"jQuery('#" + clientId + "').keyup(" +
"function(event){ " +
"if (event.keyCode == 13 || event.keyCode == 9) { " +
"var enteredText = $('#" + clientId + "').val();" +
"$('#" + clientId + "_selectBox > option').each(function(){" +
" var optionValue = $(this).val();" +
" var optionText = $(this).text();" +
" var optionDesc = $(this).attr('description');" +
" if(optionValue == enteredText) {" +
" $('#" + clientId + "').val(optionText);" +
" $('#" + clientId + "_selectBox').val(optionValue);" +
" }" +
" if(optionValue != 0) {" +
" var splitted = optionDesc.split('^');" +
" if(splitted[1] == enteredText.toUpperCase()) {" +
" $('#" + clientId + "').val(optionText);" +
" $('#" + clientId + "_selectBox').val(optionValue);" +
" }" +
" }" +
" " +
"});" +
"}" +// if for keycode ends
"});"
);
writer.write(
"jQuery('#" + clientId + "').click(" +
"function(){" +
"$('#" + clientId + "').val('');" +
"});"
);
/*writer.write("jQuery('#"+clientId+"').focus(" +
"function(){" +
"$('#"+clientId+"_selectBox').trigger('click');" +
"});"
);*/
writer.write(
"jQuery('#" + clientId + "').blur(" +
"function(){" +
"var enteredText = $('#" + clientId + "').val();" +
"$('#" + clientId + "_selectBox > option').each(function(){" +
" var optionValue = $(this).val();" +
" var optionText = $(this).text();" +
" var optionDesc = $(this).attr('description');" +
" if(optionValue == enteredText) {" +
" $('#" + clientId + "').val(optionText);" +
" $('#" + clientId + "_selectBox').val(optionValue);" +
" jQuery('#" + clientId + "_selectBox').trigger('change'); " +
" }" +
" if(optionValue != 0) {" +
" var splitted = optionDesc.split('^');" +
" if(splitted[1] == enteredText.toUpperCase()) {" +
" $('#" + clientId + "').val(optionText);" +
" $('#" + clientId + "_selectBox').val(optionValue); jQuery('#" + clientId + "_selectBox').trigger('change');" +
" }" +
" }" +
" " +
"});" +
" $('#" + clientId + "').val($('#" + clientId + "_selectBox option:selected').text());" +
"});"
);
//writer.write("jQuery('#"+clientId+"_selectBox').onmouseover(this.size=this.length)");
encodeClientBehaviors(context, menu);
writer.endElement("script");
}
protected void encodeClientBehaviors(FacesContext context, ClientBehaviorHolder component) throws IOException {
String script = "";
ResponseWriter writer = context.getResponseWriter();
String clientId = ((UIComponent) component).getClientId(context);
//ClientBehaviors
Map<String, List<ClientBehavior>> behaviorEvents = component.getClientBehaviors();
if (!behaviorEvents.isEmpty()) {
List<ClientBehaviorContext.Parameter> params = Collections.emptyList();
for (Iterator<String> eventIterator = behaviorEvents.keySet().iterator(); eventIterator.hasNext(); ) {
String event = eventIterator.next();
for (Iterator<ClientBehavior> behaviorIter = behaviorEvents.get(event).iterator(); behaviorIter.hasNext(); ) {
ClientBehavior behavior = behaviorIter.next();
ClientBehaviorContext cbc = ClientBehaviorContext.createClientBehaviorContext(
context,
(UIComponent) component,
event,
clientId,
params
);
script += behavior.getScript(cbc); //could be null if disabled
}
}
}
// SELECT Box scripts
writer.write(
"jQuery('#" + clientId + "_selectBox').change(" +
"function(){" +
"var selectedValue = $('#" + clientId + "_selectBox option:selected').text();" +
" $('#" + clientId + "').val(selectedValue);" + script +
"}" +
");});"
);
}
protected void encodeSelectItems(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> selectItems, Class type)
throws IOException {
ResponseWriter writer = context.getResponseWriter();
Converter converter = getConverter(context, menu);
Object value = menu.getValue();
for (SelectItem selectItem : selectItems) {
Object itemValue = selectItem.getValue();
String itemLabel = selectItem.getLabel();
String tLabel = itemLabel;
if (itemValue != null && !itemValue.equals("")) {
itemValue = context.getApplication().getExpressionFactory().coerceToType(itemValue, type);
}
writer.startElement("option", null);
writer.writeAttribute("description", tLabel, null);
writer.writeAttribute("value", getOptionAsString(context, menu, converter, itemValue), null);
if (value != null && value.equals(itemValue)) {
writer.writeAttribute("selected", "selected", null);
}
//if((Long)itemValue != 0) {
/*if((Long)itemValue == 209) {
writer.write(itemLabel + " [AFG]");
} else if((Long)itemValue == 203) {
writer.write(itemLabel + " [PAK]");
} else if((Long)itemValue == 205) {
writer.write(itemLabel + " [IND]");
} else {
writer.write(itemLabel + " [" + itemValue + "]");
}*/
/*}
else
writer.write(itemLabel);*/
//writer.write(itemLabel);
if (itemLabel.contains("^")) {
String[] formattedLabel = itemLabel.split("\\^");
itemLabel = formattedLabel[0] + " [" + formattedLabel[1] + "]" + " [" + itemValue + "]";
writer.write(itemLabel);
}
else {
if (itemValue instanceof Long) {
if ((Long) itemValue != 0) {
writer.write(itemLabel + " [" + itemValue + "]");
}
else {
writer.write(itemLabel);
}
}
else {
writer.write(itemLabel);
}
}
writer.endElement("option");
}
}
protected String getSelectedLabel(FacesContext context, VisionSelectOneMenu menu, List<SelectItem> items, Class type) {
Object value = menu.getValue();
String label = null;
for (SelectItem item : items) {
Object itemValue = item.getValue();
if (itemValue != null && !itemValue.equals("")) {
itemValue = context.getApplication().getExpressionFactory().coerceToType(item.getValue(), type);
}
if (value != null && value.equals(itemValue)) {
label = item.getLabel();
break;
}
}
if (label == null) {
label = !items.isEmpty() ? items.get(0).getLabel() : " ";
}
return label;
}
protected int calculatePanelHeight(VisionSelectOneMenu menu, int itemSize) {
int height = menu.getHeight();
if (height != Integer.MAX_VALUE) {
return height;
}
else if (itemSize > 10) {
return 200;
}
return -1;
}
@Override
public void encodeChildren(FacesContext facesContext, UIComponent component) throws IOException {
//Rendering happens on encodeEnd
}
@Override
public boolean getRendersChildren() {
return true;
}
protected Class getValueType(FacesContext context, VisionSelectOneMenu menu) {
ValueExpression ve = menu.getValueExpression("value");
Class type = ve == null ? String.class : ve.getType(context.getELContext());
return type == null ? String.class : type;
}
}
感谢。
答案 0 :(得分:1)
正如Oskars Pakers建议的那样,如果不访问服务器端,您将无法执行任何AJAX。在您的情况下,解决方案是将客户端的所有数据放在<option>
标记中。然而,根据您拥有的数据量,加载速度可能非常慢,如果用户不需要,您的服务器会生成不必要的代码。如果您仍然决定这样做,那么在客户端模拟自动完成行为的最佳选择是使用Select2,如果您的老板改变了主意,他们也会使用AJAX功能。