1

I have been monitoring strange behaviours in my page since I put the pageBlockTables in repeat and te columns of these tables inside a repeat too. hte recors I try to create appears on my page and I can changes the values in the inputFields, but using a button that rerender affect the values in the field. In fact, the values are simply not saved when the rerender append, or when I try to save. While debuging, I found that only the last table is functionning normally, the values are keept with a rerender and the new values in the fields updates the records. So I was wondering if using a repeat only keeps a trace of the last item in the repeat, so the other before are shown and seems to function but doesn't.

here is my VF page simplified:

<apex:page standardController="ProductRequest" recordSetVar="ProductRequest" extensions="ProductRequestController2" tabstyle="ProductRequest">
<apex:form >
    <apex:pageBlock title="Manufacturing Products Requests" id="repeat">
        <apex:repeat value="{!fieldSetsKeys}" var="fieldSetKey">
            <apex:variable var="name" value="{!fieldSetKey}"/>
            
            <apex:outputPanel styleClass="Color">
                <apex:pageBlockSection title="{!name}" columns="1">
                    <apex:pageBlockTable value="{!wrappers[name]}" var="wrapper"  id="Table">
                        
                        <apex:column headerValue="#">   <apex:outputText value="{!wrapper.ident}"/> </apex:column>
                        
                        <apex:repeat value="{!fieldSets[fieldSetKey]}" var="field">
                            <apex:column headerValue="{!fieldLabels[field]}">
                                <apex:inputField value="{!wrapper.product[field]}" />
                            </apex:column>
                        </apex:repeat>
                        
                        <apex:column headerValue="Action on row">
                            <apex:commandButton value="Clone" action="{!copyRow}" rerender="repeat">
                                <apex:param name="selectedRow" value="{!wrapper.ident}" assignTo="{!selectedRow}"/>
                                <apex:param name="productType" value="{!name}" assignTo="{!productType}"/>
                            </apex:commandButton>
                            <apex:commandButton value="Delete" action="{!deleteRow}" rerender="repeat">
                                <apex:param name="selectedRow" value="{!wrapper.ident}" assignTo="{!selectedRow}"/>
                                <apex:param name="productType" value="{!name}" assignTo="{!productType}"/>
                            </apex:commandButton>
                        </apex:column>
                    </apex:pageBlockTable>
                    
                    <apex:outputPanel>
                        <apex:commandButton value="Add Row" action="{!addRows}" rerender="repeat">
                            <apex:param name="addCount" value="1" assignTo="{!addCount}"/>
                            <apex:param name="productType" value="{!name}" assignTo="{!productType}"/>
                        </apex:commandButton>
                        <apex:commandButton value="rerender" rerender="Table"/>
                    </apex:outputPanel>
                </apex:pageBlockSection>
            </apex:outputPanel>
        </apex:repeat>
        
        
        <apex:pageBlockButtons >
            <apex:commandButton value="Save" action="{!save}"/>
            <apex:commandButton value="Cancel" action="{!cancel}"/>
            <apex:commandButton value="{!if(fileUpload == false, 'Save and add files', 'Go back')}" action="{!addAttachementFiles}"/>
        </apex:pageBlockButtons>
    </apex:pageBlock>
</apex:form>
</apex:page>

here what it looks like: enter image description here

the buttons for creating new record works well, but the problem is with the facts that the values are not kept in the inputFileds. I'm pretty sure the problem comes from the repeat, since all my code was working well when I was having a single pageBlockTable and no repeat.

And the controller:

public with sharing class ProductRequestController2 {
public List<ProductRequestWrapper> deletedWrappers {get; set;}
public Map<String, List<ProductrequestWrapper>> wrappers {get; set;}
public map<String, Id> recordTypes {get; set;}

public static map<String, String> parentRecords = new map<String, String>{'Project__c' => 'Project__c', 'Opportunity' => 'Opportunity__c'};
    public pageReference recordPage {get; set;}
public Id parentId {get; set;}
public String parentRecordApiName {get; set;}
public Boolean fileUpload {get; set;}

public String productType {get; set;}
public Integer selectedRow {get; set;}
public Integer addCount {get; set;}

public Map<String ,List<String>> fieldSets {get; set;}
public Set<String> fieldSetsKeys {get; set;}
public map<String, String> fieldLabels {get; set;}


public ProductRequestController2(ApexPages.StandardSetController controller) {
    recordPage = controller.cancel();
    fileUpload = false;
    parentId = (Id) ApexPages.currentPage().getParameters().get('id');
    if (parentId != null) {
        parentRecordApiName = parentRecords.get(parentId.getSObjectType().getDescribe().getName());
        deletedWrappers = new List<ProductRequestWrapper>();
        getRecordTypes();
        
        for (ProductRequest prod : Database.query('SELECT ' + getUsedFields() +' FROM ProductRequest WHERE ' + parentRecordApiName + ' = :parentId')) {
            String productCategoryName = prod.Product_Category__c.toLowerCase();
            wrappers.get(productCategoryName).add(new ProductRequestWrapper(wrappers.get(productCategoryName).size(), prod, true));
        }
    }
}


public void deleteRow() {
    if (wrappers.get(productType)[selectedRow].alreadyExisting == true) {
        deletedWrappers.add(wrappers.get(productType)[selectedRow]);
    }
    wrappers.get(productType).remove(selectedRow);
    
    for (Integer i = selectedRow; i < wrappers.get(productType).size(); i++){
        wrappers.get(productType)[i].ident = i;
    }
}


public void addRows() {
    for (Integer i = 0; i < addCount; i++) {
        ProductRequest newProduct = new ProductRequest(Product_Category__c = productType, recordTypeId = recordTypes.get(productType));
        newProduct.put(parentRecordApiName, parentId);
        wrappers.get(productType).add(new ProductRequestWrapper(wrappers.get(productType).size(), newProduct, false));
    }
}


public void copyRow() {
    ProductRequest copiedProduct = wrappers.get(productType)[selectedRow].product.clone(false, true, false, false);
    wrappers.get(productType).add(new ProductRequestWrapper(wrappers.get(productType).size(), copiedProduct, false));
}

public pageReference save() {
    List<ProductRequest> productsRequested = new List<ProductRequest>();
    List<ProductRequest> productsDeleted = new List<productRequest>();
    
    for (List<ProductrequestWrapper> products : wrappers.values()) {
        for (ProductRequestWrapper wrap : products) {
            ProductsRequested.add(wrap.product);
            system.debug(wrap.product);
        }
    }
    
    for (ProductRequestWrapper wrap : deletedWrappers) {
        productsDeleted.add(wrap.product);
    }
    
    try {
        upsert ProductsRequested;
    } catch(System.DMLException e) {
        ApexPages.addMessages(e);
    }
    
    if (!productsDeleted.isEmpty()) {
        delete productsDeleted;
    }
    return recordPage;
}


public pageReference cancel() {
    return recordPage;
}

public void addAttachementFiles() {
    quickSave();
    fileUpload = !fileUpload;
}


public void getRecordTypes() {
    wrappers = new Map<String, List<ProductrequestWrapper>>();
    recordTypes = new Map<String, Id>();
    
    for (Schema.PicklistEntry category : ProductRequest.Product_Category__c.getDescribe().getPicklistValues()) { //to find all picklist values
        for (RecordType recordType : [select Id, Name from RecordType where sObjectType='ProductRequest']) { //to find all possible recordType
            String categoryName = category.getLabel().toLowerCase();
            String recordTypeName = recordType.Name.toLowerCase();
            if (recordTypeName.contains(categoryName)) {
                wrappers.put(categoryName, new List<ProductrequestWrapper>());
                recordTypes.put(categoryName, recordType.Id);
            }
        }
    }
}


public map<String, Schema.FieldSet> getFieldSetMap(){
    return Schema.SObjectType.ProductRequest.fieldSets.getMap();
}


private String getUsedFields() {//for getting all the field used on the Vf page with the FieldSet and used that on the SOQL
    Set<String> usedFields = new Set<String>{'Id', 'Product_Category__c'};
        fieldLabels = new Map<String, String>();
    fieldSets = new Map<String ,List<String>>();//
    for (String fieldSet : getFieldSetMap().keySet()) {
        String fieldSetName = fieldSet.split('_')[0].toLowerCase();//
        fieldSets.put(fieldSetName, new List<String>());//
        for (Schema.FieldSetMember field : getFieldSetMap().get(fieldSet).getFields()) {
            String fieldAPI = field.getFieldPath();
            usedFields.add(fieldAPI);
            fieldLabels.put(fieldAPI, field.getLabel());
            fieldSets.get(fieldSetName).add(fieldAPI);//
        }
    }
    
    fieldSetsKeys = new Set<String>{'cable', 'plate', 'roadcase', 'pipe', 'custom'};//
        
        
        for (String lookup : parentRecords.keySet()){
            usedFields.add(parentRecords.get(lookup));
        }
    return String.join((Iterable<String>)usedFields, ' ,');
}

public class ProductRequestWrapper {
    public ProductRequest product {get; private set;}
    public Integer ident {get; private set;}
    public Boolean alreadyExisting {get; private set;}
    public Attachment file {
        get { if (file == null)
            file = new Attachment();
             return file;}
        set;}
    
    public ProductRequestWrapper(Integer inIdent, ProductRequest ExistingProduct, Boolean exist) {
        ident = inIdent;
        alreadyExisting = exist;
        product = ExistingProduct;
    }
}

}

4
  • Add the controller too
    – cropredy
    Jun 20, 2022 at 20:49
  • issue is likely to be in controller property wrappers
    – cropredy
    Jun 21, 2022 at 9:14
  • @cropredy Ok I added my controller, but I doubt the problem, is with my wrappers, since the last pageBlockTable is working correctly.
    – Alexis
    Jun 21, 2022 at 13:01
  • I also added a rerender button for each f the pageBlockTables, to confirm that something was wrong, and it happens that hitting the rerender buttons shows all the records in the last table at the place of the record of a table. So I assume that the repeat makes it that the VF page can't keep track of what is happening at the place of the tables other that the last, because it kinds of destroys the previous table at each repetition to show the next one. I have no idea how to deal with that.
    – Alexis
    Jun 21, 2022 at 13:38

1 Answer 1

2

OK I got it, the problem was that I was using a variable within my repeat. Instead o using the variable, I just used the var of the repeat and it works now.

the documentation of apex:variable says: Note: apex:variable does not support reassignment inside of an iteration component, such as apex:dataTable or apex:repeat. The result of doing so, e.g., incrementing the apex:variable as a counter, is unsupported and undefined.

This is why my code was't working. the variable was changed each time of the iteration.

1
  • 1
    ah yes -- I have run into that issue too a long time ago and forgot about the apex:variable (im)permanence
    – cropredy
    Jun 21, 2022 at 20:38

You must log in to answer this question.

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