AutoComplete CompleteMethod with AjaxBehaviorEvent

UI Components for JSF
Post Reply
Daric
Posts: 7
Joined: 08 Jun 2018, 10:39

20 Sep 2018, 10:12

Hello,

I tried to organize the question in such a way it is easy to read... thus to answer ;-). Of course, through any question you may need for better understanding of the problem.

--------------------------------------------
CONTEXT :
I am successfully dynamically creating AutoComplete components with this code :

Code: Select all

// iNmbConditions is an 'int' 
// cCondPanel is a 'UIComponent' panel 
// utils.createMethodExpression(String expression, Class<?> returnType, Class<?>... parameterTypes)	is a method successfully creating ValueMethods

// Creating the AutoComplete component
AutoComplete cAutoComplete = new AutoComplete();
// Setting general attributes
cAutoComplete.setId("critValue_" + iNmbConditions);
cAutoComplete.setMultiple(true);
cAutoComplete.setDropdown(true);
cAutoComplete.setScrollHeight(250);
cAutoComplete.setForceSelection(true);
// Setting the VALUE and CompleteMethod
cAutoComplete.setValueExpression("value", utils.createValueExpressionOnClass("#{dtColumnsQuery.critValuesMulti}",List.class));
cAutoComplete.setCompleteMethod(utils.createMethodExpression("#{dtColumnsQuery.completeValue}", null, String.class));

// Attaching the AutoComplete component to the panel
cCondPanel.getChildren().add(cAutoComplete);
The suggestions are built with this method which is called when a query is typed in the input box of the concerned AutoComplete :

Code: Select all

public List<String> completeValue(String query, AjaxBehaviorEvent e) {
	List<String> results = new ArrayList<String>();

	// aColumnName should be dynamically initialized with a LIST,
	// with index selected as same as the ID of the AutoComplete which called this method
	String aColumnName = "FIRST_NAME";
	// SQL built on the ColumnName,
	// TODO should be stored in a LIST, and not re-fired each time (see next TODO)
	String aSQL = "SELECT DISTINCT " + aColumnName + " FROM " + selectedView;
	String aValCondition = "";
	aValCondition = aColumnName + " like '%" + query + "%'";
	String aValOrderBy = aColumnName;
	ArrayList<HashMap<String, Object>> aRows = ConnectionPool.getRowsFromSelectQuery(aSQL, aValCondition, false, "", aValOrderBy);
	// Building suggestion list from the rows,
	// TODO there should be 2 Rows set,
	// origRows : original with all Rows, which should be kept
	// filteredRows : only the Rows which are left after matching 'contains' of written query from the user
	if (aRows != null) {
		for (int j = 0; j < (aRows.size() - 1); j++) {
			// System.out.println(j);
			if (aRows.get(j).get(aColumnName) != null) {
				results.add(Objects.toString(aRows.get(j).get(aColumnName).toString(), ""));
			}
		}
	}
	// Returning suggestions
	return results;
}
This works perfectly and has no issue, just an optimization to be done about the SQL queries that should be done once on the DB and not each time a key is pressed by user...

--------------------------------------------
WISH :
As is written in CompleteMethod first comment, the aim is to use the same CompleteMethod for EVERY Autocomplete component... So to be able to differentiate the calling component inside the CompleteMethod !

Here is what both, the building of the ValueMethod & the CompleteMethod should look like :
1. Building ValueMethod :

Code: Select all

// old --> cAutoComplete.setCompleteMethod(utils.createMethodExpression("#{dtColumnsQuery.completeValue}", null, String.class));
cAutoComplete.setCompleteMethod(utils.createMethodExpression("#{dtColumnsQuery.completeValue}", null, String.class, AjaxBehaviorEvent.class));
2. Signature of CompleteMethod :

Code: Select all

// old --> public List<String> completeValue(String query){...
public List<String> completeValue(String query, AjaxBehaviorEvent e){...
Resulting in this error :
SEVERE: javax.el.MethodNotFoundException: Method not found: com.data.datatable.ColumnsQuery@40a64a3d.completeValue(java.lang.String, javax.faces.event.AjaxBehaviorEvent)
--------------------------------------------
INVESTIGATIONS :
I looked in AutoComplete source code and found out that the CompleteMethod was fired with only one parameter... the query entered :

Code: Select all

    public void broadcast(javax.faces.event.FacesEvent event) throws javax.faces.event.AbortProcessingException {
		super.broadcast(event);
		
		FacesContext facesContext = getFacesContext();
		MethodExpression me = getCompleteMethod();
		
		if(me != null && event instanceof org.primefaces.event.AutoCompleteEvent) {
			suggestions = (List) me.invoke(facesContext.getELContext(), new Object[] {[b]((org.primefaces.event.AutoCompleteEvent) event).getQuery()[/b]});
            
            if(suggestions == null) {
                suggestions = new ArrayList();
            }

            facesContext.renderResponse();
		}
	}
--------------------------------------------
QUESTION :
Am I wrong and there is a way to directly find the contextual AutoComplete component which has fired the CompleteMethod ?
(With or without changing the signature of the method it's self...)

--------------------------------------------
WORKAROUND :
I, of course, could use a 'onFocus' event and set a variable with which AutoComplete was entered... but this is a workaround I will use for now, not a proper solution.


Of course, ------------> Thank you in advance for any help !!!!
PrimeFaces : 6.2
JSF : 2.2.17
Server : Tomcat 9.0.8
Java : 1.0.8_171
Eclipse : Photon Release Candidate 1 (4.8.0RC1)

Post Reply

Return to “PrimeFaces”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 30 guests