I am displaying a list of wrappers on a Visualforce search page using the table html tag and apex:repeat. The wrapper is an easy way to work with a list of PriceBookEntries and other attributes like quantity. When I display a simple list of PriceBookEntries, my rerender works fine and the search results section completely rerenders based on the search input. However, when I instead display the list with my wrappers, the search results add to the end of the list and the section does not rerender.
I can't figure out what is going on!
This works:
<!-- Search Box -->
<apex:outputPanel id="searchSection">
<div class="container">
<div class="well" id="searchBox">
<div class="row">
<div class="col-md-6">
<span id="helpBlock" class="help-block">Please search by Product Name</span>
<apex:inputText styleClass="typeahead form-control" value="{!searchText}" id="userinput" >
<apex:actionSupport event="onchange" action="{!reset}" reRender="products"/>
</apex:inputText>
<span class="input-group-btn">
<apex:commandButton value="Search" action="{!search}" styleClass="btn btn-default" reRender="products,errorPanel">
<apex:actionFunction name="search" action="{!search}" rerender="products,errorPanel"/>
</apex:commandButton>
</span>
</div>
</div>
</div>
</div>
</apex:outputPanel>
<!-- Available Products -->
<apex:outputPanel id="products">
<div class="container">
<div class="well col-md-12">
<div class="row">
<h4 style="padding-left:16px">Available Products</h4>
<div class="col-lg-8">
<div class="table table-responsive">
<table class="table table-condensed table-hover" id="availableProducts">
<tr class="info">
<th>Product Name</th>
<th>Product Type</th>
<th>Description</th>
<th>Unit Price</th>
<th>Quantity</th>
<th>Dimensions</th>
<th></th>
</tr>
<apex:repeat value="{!products}" var="prod"> <!--this is a list of PriceBookEntries -->
<tr>
<td>{!prod.name}</td>
<td>{!prod.product2.recordtype.name}</td>
<td>{!prod.product2.description}</td>
<td>£{!prod.unitprice}</td>
<td><apex:input id="quantity" value="{!selectedQuantity}" type="number" html-min="0" html-max="10">
<apex:actionSupport event="onmouseout" reRender="products" action="{!filter}"/></apex:input>
</td>
<td>height<apex:inputField id="seconddim" value="{!prod.product2.length__c}" type="number" html-min="0" html-max="100"/>columns<apex:inputField id="firstdim" value="{!prod.product2.width__c}" type="number" html-min="0" html-max="100"/></td>
<td>{!selectedQuantity}</td>
<td><apex:commandLink id="btn" action="{!addProduct}" value="Select" styleClass="btn btn-primary btn-sm" style="color:white" >
<apex:param id="selectId" name="selectId" value="{!prod.Product2Id}" assignTo="{!selectedProductId}" />
<apex:param id="selectedquantity" name="selectedquantity" value="{!selectedQuantity}" assignTo="{!tempQuantity}" />
</apex:commandLink></td>
</tr>
</apex:repeat>
</table>
<nav>
<ul class="pager">
<li><a href="#">Previous</a></li>
<li><a href="#">Next</a></li>
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</apex:outputPanel>
This does not work (the search results only make the table larger, rather than refreshing the results):
<apex:repeat value="{!productWrappers}" var="prod">
<tr>
<td>{!prod.name}</td>
<td>{!prod.recordTypeName}</td>
<td>{!prod.description}</td>
<td>£{!prod.unitprice}</td>
<td><apex:input id="quantity" value="{!prod.quantity}" type="number" html-min="0" html-max="10">
<apex:actionSupport event="onmouseout" reRender="products" action="{!tempMethod}" status="fetchStatus"/></apex:input>
<apex:outputPanel style="color:#4AA02C;font-weight:bold">
<apex:actionStatus id="fetchStatus" startText="Please wait..." stopText=""/>
</apex:outputPanel>
</td>
<td>{!prod.height} x {!prod.columns}</td>
<!--<td>height<apex:input id="seconddim" value="{!prod.height}" type="number" html-min="0" html-max="100"/>columns<apex:input id="firstdim" value="{!prod.columns}" type="number" html-min="0" html-max="100"/></td>-->
<td><apex:commandLink id="btn" action="{!addProduct}" value="Select" styleClass="btn btn-primary btn-sm" style="color:white" >
<apex:param id="selectId" name="selectId" value="{!prod.pbeId}" assignTo="{!selectedProductId}" />
<apex:param id="selectedquantity" name="selectedquantity" value="{!prod.quantity}" assignTo="{!tempQuantity}" />
</apex:commandLink></td>
</tr>
</apex:repeat>
My wrapper class:
/*
* Pricebookentry Wrapper Class
* @params: PriceBookEntry p
*/
public class productWrapper {
public String pbeId {get; set;}
public String productId {get; set;}
public String name {get; set;}
public Decimal unitPrice {get; set;}
public String description {get; set;}
public Decimal salesPrice {get; set;}
public Integer quantity {get; set;}
public String recordTypeName {get; set;}
public Decimal height {get; set;}
public Decimal columns {get; set;}
public productWrapper(Id pricebookentryId){
PriceBookEntry p = [select id,product2id,name,unitprice,product2.description,product2.recordtype.name,product2.length__c,product2.width__c from PriceBookEntry where id=:pricebookentryId];
this.pbeId = p.Id;
this.productId = p.Product2Id;
this.name = p.name;
this.unitPrice = p.UnitPrice;
this.description = p.Product2.Description;
this.recordTypeName = String.valueOf(p.product2.recordtype.name);
this.height = p.product2.length__c;
this.columns = p.product2.width__c;
}
}
And the method to call it:
/*
* Returns list of product wrappers for 'products' section of VF page
* @params: list<Pricebookentry> pbes
*/
public list<productWrapper> getProductWrappers(list<PriceBookEntry> pbes){
for(PriceBookEntry pbe : pbes){
productWrapper pwrap = new productWrapper(pbe.id);
productWrappers.add(pwrap);
}
return productWrappers;
}