14

I have an editable page block table displaying SObjects records per row. There are also actions per row that only modify the row's record.

<apex:pageBlockTable>
    <apex:column><apex:commandButton action="{!doRowAction}"/></apex:column>
    <apex:column/>
    <apex:column/>
</apex:pageBlockTable>

To reduce loading time and prevent irrelevant validation errors (those of other rows) I want to restrict the rerendering to a single row.

<apex:pageBlockTable>
    <apex:actionRegion renderRegionOnly="true">
        <apex:column><apex:commandButton action="{!doRowAction}"/></apex:column>
        <apex:column/>
        <apex:column/>
   </apex:actionRegion
</apex:pageBlockTable>

The problem is this doesn't save!

Error: <apex:column> must be the direct child of either <apex:dataTable> or <apex:pageBlockTable>

Edit: We also tried to rebuild the table in plain HTML using apex:repeat but ran it another yet unsolved problem.

3
  • 2
    If you want this granular of control, you will almost certainly need to go with a Javascript Framework like angular or React.
    – Adrian Larson
    Feb 26, 2016 at 16:25
  • I'm with Adrian. Though I used only jQuery for it.... Angular and React were overkill (for me, perhaps not for you) Mar 1, 2016 at 20:22
  • This is just tossing out an idea for consideration. Have you considered trying to do this using unordered list elements <Ul> and <li> with CSS instead of tables as a workaround to these constraints?
    – crmprogdev
    Mar 3, 2016 at 14:49

3 Answers 3

4

I found a way to rerender the rows while only processing the row you're on. I will try to outline the concept here but a a full description of my solution can be found here:

Visualforce: Dynamically ReRender a row within <apex:repeat> by passing $Component through controller

Clarify Action Region:

As you probably already realize, the actionRegion tag will focus your form to only process the fields contained by it, "it does not define what area(s) of the page are re-rendered when the request completes". I personally didn't have this requirement.

Action Function Approach:

I am unsure what you expect the user experience to be like, in my example the values bound to the controller are updated every time the user makes a change to the inputText using the onchange event to trigger an actionFunction. In this instance I iterated through my repeat with a map (3 levels deep) and dynamically passed the map indexes so that my controller could figure out which "row" of data to set/process.

Example of operations:

  1. Form Markup:

    <apex:inputText onChange="jsMethod(this)">

  2. JS Function:

    jsMethod(row){ actionMethod(params) }

  3. VF Action Function:

    <apex:actionFunction action="{!ctrlCustomSetter}" rerender="{!$Component.myRepeater.myRowId}" />

  4. Controller PageReference Method:

    PageReference ctrlCustomSetter(){ String var = String.valueOf(ApexPages.currentPage().getParameters().get('myvar')); }

Command Button Approach:

You could however use an actionSupport on your command button to also pass the indexes to your controller. Depending on your user interaction you may need some jQuery to set those parameters, but I find its much easier manipulate my list of data as the user interacts with it (onChange) and then just process the data on submission.

Now the key to rerendering the rows and not the complete container is to generate the component id in the rerender attribute, you cannot "pass" the value through a controller variable like so: rerender="{!rowID}", this will not work. Rather select the component you want like so:

rerender="{!$Component.myRepeaterId.myRowId}"

I am not 100% this answer meets your requirements but I believe there is overlap with both of our issues so I felt it was worth posting in case it helps you at all (hopefully it doesn't get scrutinized too much). Good Luck!

1
  • Even this does not work in my case : salesforce.stackexchange.com/questions/253012/… When the component is created I can see the span tag has an id like this : idPageCreateCase:j_id86:idPageComponent:idForm:outerOutput0 , and rerender atribute too has an ID like this, but still the rerender does not happen properly. Mar 8, 2019 at 2:34
-4

You need to put the actionRegion tag inside the column tag. And if you only want to edit the specific row, you'll want to add params inside your command button. Something like this:

<apex:column>
    <apex:actionRegion>
        <apex:commandButton action="{!myAction}" rerender="{!someTableArea}">
            <apex:param name="myParam" assignTo="{!myParam}" value="{!someValue}" />
        </apex:commandButton>
    </apex:actionRegion>
<apex:column>

Then, use myParam in your action method. You need to define myParam with a get/set at the top class level.

You can conditionally render the apex:commandButton based on whatever you want.

3
  • 2
    How would helping this with my problem of only wanting to refresh/rerender/sync the state of the row. What you suggest will only do this with a single field. Feb 28, 2016 at 12:43
  • 1
    Can you show me what your controller code looks like? What kind of objects are you iterating over? Are they wrapper objects, a list of sObjects, etc? Feb 29, 2016 at 20:08
  • "Note that an <apex:actionRegion> component only defines which components the server processes during a request—it does not define what area(s) of the page are re-rendered when the request completes" developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/… Jun 8, 2016 at 19:36
-4

You can't rerender a single row in a pageBlockTable. One method that I've used is with jQuery. Set an onClick event in your button that will loop through all the input fields and remove the required attribute. You can have the onclick event return true so that your action method can occur. This way you can rerender your entire table without getting the validation errors.

In your button, you want to add a parameter so your controller knows which specific object to do action on.

Here's some VF markup:

<apex:page docType="HTML-5.0" controller="SomeController">
<apex:outputPanel id="panel">
    <apex:pageBlockTable value="{!myObjects}" var="o">
        <apex:column>
            <apex:inputField id="requiredField" value="{!o.Field__c}" required="true" />
        </apex:column>
        <apex:column>
            <apex:commandButton onClick="forgetRequiredFields()" action="{!doMyAction}" rerender="panel">
                <apex:param name="objectId" value="{!o.Id}" assignTo="{!sObjectActionId}" />
            </apex:commandButton>
         </apex:column>
     </apex:pageBlockTable>
</apex:outputPanel>
</apex:page>

You can define the javascript function for your onclick action in the command button with jQuery like this: (ps - you need to include jQuery for this bit to work)

<script>
    function forgetRequiredFields(){
        $('.requiredField').each(function(){
            $(this).prop('required',false);
        });
        return true;
    }
</script>

Then, in your controller you'd have this

public Id sObjectActionId{get;set;}
public void doMyAction(){
    for(sObject s: myObjects){
        if(s.Id == sObjectActionId){
          //do something with your object
            break;
        }
    }
}

The controller will find the specific object you're acting on and perform logic only on that one. Just give the input fields you want to manipulate a specific Id, or something selectable via jQuery, and you can modify the dom as needed.

Let me know if this helps.

5
  • 1
    Did you really try this out?! Doesn't work for me and I am quite sure that I know why. In your Javascript your are trying to modify attributes that never appear in the page DOM as they are only Visualforce tags (required attribute of .requiredField). Mar 2, 2016 at 10:34
  • 1
    Could you please be so kind an either correct your code or remove both this answer. Mar 2, 2016 at 10:34
  • 1
    I don't belive you got this running. Visual Force is rendered to regular HTML, so there is no 'required' attribute on <input> elements. This is not a solution!
    – itsmebasti
    Mar 2, 2016 at 10:36
  • this works on my page - try adding the docType="HTML-5.0" to the <apex:page> tag. Mar 2, 2016 at 14:23
  • 1
    I tried it, and there actually is an attribute called 'required', but changing it to false, does still not change the buttons behaviour. Still the same error message: You must enter a value! I'm still sure that <input required> is not related/connected to the apex:inputField required attribute.
    – itsmebasti
    Mar 2, 2016 at 15:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .