You need to sign in to do that
Don't have an account?
Filter pageBlockTable as you type
Hey everyone,
I have an application where I need to impliment a filter as you type system. Basically we have a pageBlockTable that loads a few hundered records. My users want to be able to have a text field where they can begin typing the name of a person and have the results in the pageBlockTable filter to match their query. I figure someone else must have already done this and figured I'd ask the community before I try and hammer it out myself. If I were going to do it, I figure the approach would be
1) Find all people and populate the pageBlockTable
2) Create text field with onKeyUp event tied to apexActionFunction
3) apexActionFunction sends current value in filter box to an apex method
4) apex method makes a backup of the complete list. Then queries against the original using the parameters provided by the user.
5) return the new filtered list to the pageBlockTable
6) reRender the table.
The only part I don't really know how to do is to filter against the list I already have, as opposed to running a whole new SOQL query against the DB (which would be super inefficient). How can I filter a list that exists in the heap instead of running a few query?
Between 50 and 300 rows or so. I was a bit worried about performance, but I figured I'd cross that bridge when I come to it.
ok, so here's the general strategy:
so here's the general strategy. i can't provide sample code because ours is heavily customized and you'd lose a lot in the translation. you're not using the standard controller, you're using a custom one
tips:
Good information, thank you.
I havn't done binding before, that basically just means that value in the box will be the value in the variable as apex sees it correct? So I can avoid doing any value passing (as far as the actual search string is concerned) like I normally would have to?
Also, you are saying I should just run fresh SOQL queries instead of of somehow trying to query against the full list I already have in memory? If so thats fine, just making sure I understand.
Thanks again.
I actually decided to scrap the filter as you type. Just a simple search button will work for now. I think I have everything set up, but my filter doesn't actually do anything. It always returns everyone for that campaign. It's like it just doesn't do anything.
Below are the revelevant VF and apex chunks
APEX
public void getData()
{
//This function is responsible for building a list of respondents based on a master campaign Id
if(respondents != null)
{
respondents.clear();
}
//Find the Id of the selected campaign
campaignId = Apexpages.currentPage().getParameters().get('campaignId');
//Find if the user has entered any kind of search string
searchQueryString = Apexpages.currentPage().getParameters().get('respondentSearch');
if(searchQueryString == null)
{
searchQueryString = '%';
}
else
{
searchQueryString = '%' + searchQueryString + '%';
}
system.debug('------------------------------------------------------------------------------------------------');
system.debug('Searching for '+searchQueryString);
system.debug('------------------------------------------------------------------------------------------------');
//If the campaignId has been populated
if(campaignId != null)
{
system.debug('------------------------------------------------------------------------------------------------');
system.debug('Searching for respondents in'+campaignId);
system.debug('------------------------------------------------------------------------------------------------');
respondents = [SELECT Id,
Respondent_Check_In_Status__c,
Respondent__r.FirstName,
Respondent__r.Id,
Respondent__r.LastName,
Respondent__r.PID__c,
Respondent__r.Gender__c,
Respondent__r.Phone,
Respondent__r.Email,
Respondent__r.Birthdate,
Respondent__r.Organization1__c,
Respondent__r.HiddenOrgName__c,
Respondent__r.Age__c,
Criteria_1_Hidden__c,
Criteria_2_Hidden__c,
Criteria_3_Hidden__c,
Criteria_4_Hidden__c,
Criteria_5_Hidden__c,
Criteria_6_Hidden__c,
Criteria_7_Hidden__c,
Criteria_8_Hidden__c,
Criteria_9_Hidden__c,
Criteria_10_Hidden__c,
Child_Campaign__r.Incentive_Amount_Paid_for_Study__c,
Child_Campaign__r.Time_Slot__c,
Master_Campaign__r.Contribution_Amount__c,
Master_Campaign__r.Criteria_1__c,
Master_Campaign__r.Criteria_2__c,
Master_Campaign__r.Criteria_3__c,
Master_Campaign__r.Criteria_4__c,
Master_Campaign__r.Criteria_5__c,
Master_Campaign__r.Criteria_6__c,
Master_Campaign__r.Criteria_7__c,
Master_Campaign__r.Criteria_8__c,
Master_Campaign__r.Criteria_9__c,
Master_Campaign__r.Criteria_10__c,
Respondent__r.MailingStreet,
Respondent__r.MailingPostalCode,
Respondent__r.MailingState,
Respondent__r.MailingCity,
Respondent__r.MobilePhone
From Respondent__C where Master_Campaign__c = :campaignId and Respondent__r.firstname like :searchQueryString];
}
}
VF
<apex:actionFunction action="{!getData}" name="filterRespondentList" status="filtering" reRender="cmTable">
<apex:param name="respondentSearch" value="" />
</apex:actionFunction>
Find Respondent: <input type="text" id="respondentName" />
<apex:commandButton title="Find" value="Find" onclick="filterRespondentList(respondentName.value);" />
Heck, if your table initially loads with all of the data I'd probably just filter it in the browser with javascript rather than having the server do this. Wouldn't be that hard to iterate over the table rows and and set display:none. Even easier with something like jQuery.
like the jQuery solution, but it's hard to isolate elements in VF because of the crazy ID's it gives everything as far as I know. Any tips for if I approach it this way? I can probably hack something together, but my guess is anything you got is probably a lot more elegant than whatever I'll come up with.
This visualforce markup...
....will render this HTML....
...and this jQuery function will filter the table....
Your IDs will most likely be different and you will need to updated the jQuery but this should get you well on your way.
-Jason
Thank you sir, you are a gentleman and a scholar ;)
I really appreciate it. I'll let ya know if I have questions.
Ken,
I highly suggest using the styleClass to give your elements unique ids of your own choosing and then referencing them with ('.myUniqueId').doSomething();
That's a really good idea. I forgot jQuery can select based on css class, so yeah, just assign my elements some specific class and use that to select them. Good thinking! Thanks!
Notes: (1) only a tiny bit slower than the id. (2) works on virtually all VF elements (except inputFields)
Style class is an option but I had this example laying around and it is tuned for performance over developer friendliness. Finding elements by class name can be a lot (i think more than tiny) slower on older browsers.
I do remember selecting based on css class to be slower, though this is going to be an internal only application so I can control what browsers are getting to it. I'll certainly keep it in mind. Either way, it's good to have options, so thanks to you both for your exellent insight.
I had a conversation about this in the jQuery IRC room since I wasn't sure about the speed and had read a little about it elsewhere. The conclusion (including input from jQuery core team members) is that since the css style attribute selection is handled by jQuery it is only marginally slower and will barely affect performance. This is true in my experience although I've not spent a lot of time in older browsers.
Thanks Kenji! Good luck!
Intresting to hear. From what I understood jQuery uses the native getElementByClassName (very fast) if it is supported by browser (everything but IE) and if not it must traverse the entire DOM. May not be that bad if you are only getting one element but if used in a loop milliseconds can add up fast.
EDIT: Confirmed, it does use native getElementsByClassName if supported: http://api.jquery.com/class-selector/
Makes sense. Probably worth doing some diagnostics somehow at some point. Plz post to your blog if you do and I'll do the same.