I'm creating a custom community chatter answers page and I have multiple questions with answers in them using an apex repeater. The problem is that because it's repeating inputText field (for posting replies), it is using the same value variable, like this (postAnswer):
VF Page
<apex:form>
<apex:variable var="questionIndex" value="{!0}" id="index" />
<apex:repeat value="{!wrapperQuestions}" var="currentQuestion">
<div class="articleWrapper clearfix">
<apex:outputPanel>
<article class="whiteCard socialCard">
<span class="category">Answers</span>
<div class="clearfix">
<div class="profilePic centerAlign col _1of6">
<apex:image url="{!currentQuestion.question.CreatorFullPhotoUrl}" />
<span class="heading7">Frequent Poster</span>
</div>
<div class="col colPad content _5of6">
<h1 class="heading1">{!currentQuestion.question.Title}</h1>
<h2 class="heading6">
<strong>{!currentQuestion.question.CreatedBy.Name}</strong> —
<apex:outputText value="{0,date,E MMM d, yyyy 'at' hh:mma z}">
<apex:param value="{!currentQuestion.question.CreatedDate}"/>
</apex:outputText><br />
</h2>
<p>{!currentQuestion.question.Body}</p>
<div class="rightAlign">
<button type="button" class="readMore">Read More <i class="fa fa-caret-down"></i></button>
</div>
</div>
</div>
</article>
</apex:outputPanel>
<div class="whiteCard newPost">
<apex:inputText id="postAnswer" value="{!currentQuestion.postAnswer}" html-placeholder="What do you have to say?" />
<apex:commandButton action="{!saveReply}" styleClass="post" value="Post" rerender="replies,index">
<apex:param name="qId"
value="{!currentQuestion.question.Id}"
assignTo="{!qId}"/>
<apex:param name="questionIndex"
value="{!questionIndex}"
assignTo="{!questionIndex}"/>
</apex:commandButton>
</div>
<apex:repeat value="{!currentQuestion.bestReply}" var="bestReply">
<apex:outputPanel rendered="{!bestReply.Id != null}">
<div class="replies col colRight _3of4">
<div class="whiteCard socialCard">
<span class="category">Best Answer <i class="fa fa-check-circle"></i></span>
<div class="clearfix">
<div class="profilePic centerAlign col _1of6">
<apex:image url="{!bestReply.CreatorSmallPhotoUrl}" />
</div>
<div class="col colPad content _5of6">
<h2 class="heading6">
<strong>{!bestReply.CreatedBy.Name}</strong> —
<apex:outputText value="{0,date,E MMM d, yyyy 'at' hh:mma z}">
<apex:param value="{!bestReply.createdDate}"/>
</apex:outputText>
</h2>
{!bestReply.Body}
</div>
</div>
</div>
</div>
</apex:outputPanel>
</apex:repeat>
<apex:repeat value="{!currentQuestion.replies}" var="currentReply" id="replies">
<apex:outputPanel rendered="{!currentReply.Id != null}">
<div class="replies col colRight _3of4">
<div class="whiteCard socialCard">
<div class="clearfix">
<div class="profilePic centerAlign col _1of6">
<apex:image url="{!currentReply.CreatorSmallPhotoUrl}" />
</div>
<div class="col colPad content _5of6">
<h2 class="heading6">
<strong>{!currentReply.CreatedBy.Name}</strong> —
<apex:outputText value="{0,date,E MMM d, yyyy 'at' hh:mma z}">
<apex:param value="{!currentReply.createdDate}"/>
</apex:outputText>
</h2>
{!currentReply.Body}
</div>
</div>
</div>
</div>
</apex:outputPanel>
</apex:repeat>
</div>
<apex:variable var="questionIndex" value="{!questionIndex + 1}"/>
</apex:repeat>
Since it's the same value, I can only get the value of the last input field and none of the other ones in my controller.
Here's my controller. It doesn't have much. Just to test that I'm getting the correct values:
Controller
public with sharing class RL_HubHome {
public Id currentUserId {
get;
set;
}
public String currentUserName {
get;
set;
}
public String currentUserOrganization {
get;
set;
}
public String currentUserProfileImageLarge {
get;
set;
}
public Integer totalSubscribedGroups {
get;
set;
}
public Integer totalSubscribedAnswers {
get;
set;
}
public Integer totalCases {
get;
set;
}
public Integer totalIdeas {
get;
set;
}
public String strFilteredDataCategories {
get;
set;
}
public List < WrapperQuestions > wrapperQuestions {
get;
set;
}
public WrapperQuestions wq {
get;
set;
}
public List < Question > questionsList {
get;
set;
}
public list < String > listSubscriptionCategories {
get;
set;
}
public String postAnswer {
get;
set;
}
public String qId {
get;
set;
}
public Integer questionIndex {
get;
set;
}
public String searchCategory;
public String getsearchCategory() {
return searchCategory;
}
public void setsearchCategory(String searchCategory) {
this.searchCategory = searchCategory;
}
public RL_HubHome() {
init();
}
public Pagereference redirectUnAuthenticatedUser() {
if (Userinfo.getUserType() != 'CspLitePortal' && Userinfo.getUserType() != 'PowerCustomerSuccess') {
return new Pagereference('/Signin');
}
return null;
}
private void init() {
currentUserId = Userinfo.getUserId();
currentUserName = Userinfo.getName();
currentUserOrganization = Userinfo.getOrganizationName();
currentUserProfileImageLarge = [SELECT FullPhotoUrl FROM User WHERE Id = : currentUserId].FullPhotoUrl;
totalSubscribedGroups = [SELECT count()
FROM CollaborationGroupFeed
WHERE ParentId IN(
SELECT CollaborationGroupId
FROM CollaborationGroupMember
WHERE MemberId = : currentUserId)];
totalSubscribedAnswers = [SELECT count()
FROM QuestionSubscription q
WHERE q.SubscriberId = : currentUserId];
totalCases = [SELECT count()
FROM Case
WHERE IsDeleted = false
AND IsClosed = false
AND CreatedById = : currentUserId];
totalIdeas = [SELECT count()
FROM Idea i
WHERE i.CreatedById = : currentUserId];
strFilteredDataCategories = RL_FetchDataCategoryOfLoggedInUser.dataCatgeries();
wrapperQuestions = getQuestionsReplies();
listSubscriptionCategories = new List < String > ();
listSubscriptionCategories.add('All');
listSubscriptionCategories.add('Answers');
listSubscriptionCategories.add('Ideas');
listSubscriptionCategories.add('Groups');
}
public List < Question > getQuestions() {
if (questionsList == null) {
questionsList = new List < Question > ();
for (Question q: [SELECT q.Id, q.CreatorSmallPhotoUrl, q.CreatorFullPhotoUrl, q.CreatorName, q.CreatedDate, q.CreatedById, q.CreatedBy.Name, q.Body, q.Title, q.BestReplyId FROM Question q]) {
// As each question is processed we create a new WrapperQuestions object and add it to the questionList
questionsList.add(q);
}
}
return questionsList;
}
public List < WrapperQuestions > getQuestionsReplies() {
WrapperQuestions wrapperQuestions;
List < WrapperQuestions > wrapperList = new List < WrapperQuestions > ();
if (questionsList == null) {
List < Question > questionsList = getQuestions();
List < Reply > replies;
for (Question q: questionsList) {
Reply bestReply = null;
List < Reply > bestReplyList = new List < Reply > ();
List < reply > repliesList = new List < reply > ();
// As each question is processed we create a new WrapperQuestions object and add it to the repliesList
bestReplyList = [SELECT Id, CreatedDate, CreatedById, CreatedBy.Name, CreatorName, QuestionId, Body, UpVotes, DownVotes, CreatorSmallPhotoUrl FROM Reply WHERE QuestionId = : q.Id AND Id = : q.BestReplyId];
if (!bestReplyList.isEmpty()) {
bestReply = bestReplyList[0];
}
replies = [SELECT Id, CreatedDate, CreatedById, CreatedBy.Name, CreatorName, QuestionId, Body, UpVotes, DownVotes, CreatorSmallPhotoUrl FROM Reply WHERE QuestionId = : q.Id AND Id != : q.BestReplyId ORDER BY CreatedDate ASC];
if (replies != null) {
for (Reply r: replies) {
repliesList.add(r);
}
} else {
repliesList = null;
}
wrapperQuestions = new WrapperQuestions(q, bestReply, repliesList);
wrapperList.add(wrapperQuestions);
}
}
return wrapperList;
}
public class WrapperQuestions // wrapper class to handle multiple objects.
{
public Question question {
get;
set;
}
public Reply bestReply {
get;
set;
}
public List < Reply > replies {
get;
set;
}
public String postAnswer {
get;
set;
}
public WrapperQuestions(Question q, Reply bestR, List < Reply > r) {
bestReply = bestR;
question = q;
replies = r;
}
}
public void saveReply() {
System.Debug('====qId===' + qId);
//System.Debug('===postAnswer===' + wrapperQuestions[questionIndex].postAnswer);
postAnswer = wrapperQuestions[questionIndex].postAnswer;
System.Debug('===postAnswer===' + postAnswer);
try {
// Add a reply to this question.
Reply r = new Reply(
QuestionId = qId,
Body = postAnswer);
insert r;
} catch (DmlException e) {
System.debug('An unexpected error has occurred: ' + e.getMessage());
}
}
}
Thanks in advance!
bestReplyList
andreplies
out of thatfor
loop overquestionsList
. Queries in loops is a bad practice.WHERE QuestionId = : q.Id AND Id = : q.BestReplyId
, add the question IDs and best reply IDs to Sets beforehand making a single query with the conditionWHERE questionId IN :setOfQuestionIds AND Id IN :setOfBestReplyIds
. You now have all the relevant records with a single query, and can process them with Apex. See SFDC99's series of posts for details - sfdc99.com/2014/01/20/soql-queries-inside-loops