0

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> &mdash;
                        <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> &mdash;
                                <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> &mdash;
                                <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!

  • 1
    Before you're done with this page, refactor the SOQL queries for bestReplyList and replies out of that for loop over questionsList. Queries in loops is a bad practice. – Mark Pond Aug 21 '15 at 18:49
  • Thanks Mark. What is the alternative to this? I'm trying to get all replies related to all questions. The only way that I can think of going about it is to have a repeater inside a repeater to display the values. – slim Aug 21 '15 at 19:23
  • Rather than having multiple SOQL queries with the conditions 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 condition WHERE 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 – Rob Aug 25 '15 at 7:30
1

The problem is that there's a single postAnswer for multiple wrapperQuestions. The way to fix this is to move postAnswer into your wrapper class so that it becomes a property of each wrapperQuestion. You can then change the value of the apex:inputText to {!currentQuestion.postAnswer}.

When you call saveReply(), each wrapperQuestion will now have its own postAnswer. To know which one has been submitted, you need to submit the wrapperQuestion's position index in the list. To do this, add the following:

Before the opening tag of <apex:repeat> -

<apex:variable var="questionIndex" value="{!1}" />

Before the closing tag of <apex:repeat> -

<apex:variable var="questionIndex" value="{!questionIndex + 1}"/>

Add questionIndex as another <apex:param> to the <apex:commandButton>, then in the saveReply() method your answer will be wrapperQuestions[questionIndex].postAnswer.

| improve this answer | |
  • Thanks Rob, but I think I was unclear. The inputText field is supposed to be empty and filled in by the user and then the value of this needs to be passed to the controller. – slim Aug 21 '15 at 15:05
  • Understood. In that case, you may need to change the type of postAnswer from a String to a list of Strings. It's hard to tell from the code above. Can you post more of the page (specifically the <apex:repeat>) and the controller please? – Rob Aug 21 '15 at 15:09
  • Added my controller, but it doesn't show much. I'm just using the button to debug what values are passed back. In my case I need to pass back the reply and the questionId - So I can post the reply into the database for the correct question. – slim Aug 21 '15 at 15:13
  • Thanks for posting the controller, but it's still hard to tell what's going on - you aren't repeating anything in the code above. – Rob Aug 21 '15 at 15:16
  • This is just a snippet. I can post the entire thing so you can see what's happening if it helps. – slim Aug 21 '15 at 15:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.