+ Start a Discussion
Ken KoellnerKen Koellner 

javascript remoting to fill pageblocktable and other tags in hybrid

I need to develop a page with a very large grid of data.  I'm affraid it may exceed view state limits.

I know I could code it all in HTML with my choice of JS framework with JS remoting to get an write data.  But that's is an increased coding effort and also loses the SF look and feel.

What I'd like to do instead of develop some sort of hybrid page.  Use the VF tags like pageBlockTable column, etc. to get the SF look, but then on pageload have a script call javascript remote actions to get the full data which would be larger than 136K view state.  Then have various onChange events save pieces of data back to SF via other remove actions.  The only merge variable needed would be a master id to provide the intial script with a key so it could compose the calls to remote actions.

I wondering if maybe there could be some dummy empty tables and then a way to get scripts to fill them with data.

Anyone know if that architecture is doable and maybe have some examples anything like that?
ShashankShashank (Salesforce Developers) 
Please see if these links help:
http://salesforce.stackexchange.com/questions/11825/display-javascript-result-in-a-pageblocktable
http://stackoverflow.com/questions/22887879/vf-pageblocktable-w-javascript-and-conditional-behavior

Ken KoellnerKen Koellner
The second link doesn't seem to be apropos to what I'm trying to do.

The first link is close.  What it does is provide a way to create a vanilla HTML table that looks like a pageBlockTable because it uses the same styles.  It doesn't behave like one as it doesn't have the highlighting JS on it.  But it still doesn't look bad and may indeed be useful.

I considiered putting appropriate events on the rows to get the VF pageBlockTable highlighing.  But SF doesn't consider it a good programming technique to call there routines.  In any future release, if they change stuff, your page will break.

ministe2003ministe2003
Sorry to dredge up an old thread but I wanted to do the same thing as you and managed to find a way to pull it off.  Before I explain I should say up front that doing this reduces the benefit of remoting because it slows the process down.

What I wanted to achieve
To be able to run a query to retreive a list of accounts using Javascript Remoting and display results in a pageblock table, in order take advantage of remoting's great speed.

The problem
The only solution involved having to inject the table into the page using script - I wanted a native pageblocktable right there in the DOM which I could just reRender to show the new results.  Whilst other examples say to store results in an inputHidden component in order to pass it back to the controller, this doesn't work for lists because the variable is expecting a List<Account> but the component passes back a string even if you parse the JSON first.

The Solution
When you receive the results in the callback, put them into an apex:inputHidden field whos value points to a String apex variable whos setter immediately decodes the JSON and puts the list into a List<Account> variable.  The pageblocktable uses that List<Account> variable, and when the script is finished, it calls an apex:actionFunction to reRender the table.

Positives
  • Involves almost no script so the majority of the work is native apex and visualforce
  • You're able to change the query without having to worry about updating a hard-coded injected table within your script
Negatives
  • You lose a lot of the increased speed that remoting provides so your results will not refresh much quicker than using completetly native code
End result
I actually ended up going down the html injection route after all due to its massively improved performance over either this hybrid method or the fully native method, but it was still a good exercise to find this solution which I've not seen offered up elsewhere.

Code
Apex
//Assign this as the pageBlockTable's value
public List<Account> accResults {get;set;}

/*
This is what you'll assign the inputHidden value to.
It receives the JSON result, unescapes it (you should only need to worry about that
if using a serialized query result rather than passing a serialized wrapper class)
then assignes the deserialized list to another variable, above.
The getter returns null because I don't need anything returned to the inputHidden component
*/
public String accResult {
	get{
		return null;
	}
	set{
		String jsonStr = value.unescapeHtml4();
		accResults = (List<Account>)JSON.deserialize(jsonStr, List<Account>.class);
	}
}

@remoteAction
public static String queryAccounts(String searchTerm){
    String qry = 'SELECT Id, Name, BillingCountry FROM Account WHERE Name = \''+searchTerm+'\' ORDER BY Name ASC LIMIT 500';
    return JSON.serialize(database.query(qry));
}

Visualforce Page and Script
...

<script type="text/javascript">
	var $j = jQuery.noConflict();
	$j(document).ready(function() {
		//click handler for button
		$j("#searchAccs").click(function() {
			//call the function and perform query
			myController.queryAccounts($j('[id$=t1AccName]').val(),function (result, event){
				if(event.status){
					//pass the result into the inputHidden.  This will run the setter function
					//which passes the list of accounts into the List<Account> variable
					$j('[id$=resultHolder]').val(result);
					//call the actionFunction to refresh the pageBlockTable
					refresh();
				}else{
					console.log(event.message);
				}
			});
		});
	});
</script>

...

<apex:form>
	<apex:actionFunction name="refresh" reRender="resultBlock"/>
	<apex:pageBlock>
		<apex:pageBlockSection id="resultBlock">
            <label for="t1AccName">Account Name</label>
            <apex:InputText id="t1AccName"/>
            <input type="button" id="searchAccs" value="Search" />

            <!-- This will receive the JSON results -->
			<apex:inputHidden value="{!accResult}" id="resultHolder" />
			<!-- this will display the list of results -->
			<apex:pageBlockTable value="{!accResults}" var="a">
				<apex:column value="{!a.Name}" />
				<apex:column value="{!a.BillingCountry}" />
			</apex:pageBlockTable>
		</apex:pageBlockSection>
	</apex:pageBlock>
</apex:form>

...