0

I have two objects in my org question and answer which has a lookup relationship between them. I wanted to create a LWC component which displays one question with multiple answers but I am unable to display it.

I have written the following apex code which I am using in my LWC to components to render on the UI

Apex Controller:

public with sharing class ControllerClass {
    @AuraEnabled(cacheable = true)
    public static List<wrapperClass> getWrapperClassList() {
        List<wrapperClass> wrapperList = new List<wrapperClass>();

        Map<Id, Ques__c> mapOfQuestions = new Map<Id, Ques__c>([SELECT Id, Content__c FROM Ques__c]);  

        List<Ans__c> listOfAnswers = [SELECT Id, Name, Ques__r.Id, Ques__r.Content__c
                                        FROM Ans__c 
                                        WHERE Ques__r.Id 
                                        IN :mapOfQuestions.keyset()];

        System.debug('listOfAnswers==='+listOfAnswers);
        for(Ans__c answer : listOfAnswers){
            wrapperClass wc = new wrapperClass();
            wc.questionId =  answer.Ques__r.Id;
            wc.questionContent = answer.Ques__r.Content__c;
            wc.answerId = answer.Id;
            wc.answerName = answer.Name;
            wrapperList.add(wc);
        }

        return wrapperList;
    }

    public class wrapperClass{
        @AuraEnabled
        public String questionId;
        @AuraEnabled
        public String questionContent;
        @AuraEnabled
        public String answerId;
        @AuraEnabled
        public String answerName;
    }

}

Question.html

<template>
    <lightning-card title="Question">
        <template for:each={wrapperList.data} for:item="wrapper" >
            <p class="slds-m-left_medium" key={wrapper.questionId}>
                 {wrapper.questionContent}
            </p> 
       </template>
    </lightning-card>
</template>

Question.js

import { LightningElement, wire } from 'lwc';
import getWrapperClassList from '@salesforce/apex/ControllerClass.getWrapperClassList'; 

export default class Question extends LightningElement {
    @wire(getWrapperClassList)
    wrapperList;
    
}

Answer.html:

<template>
    <lightning-card class="slds-m-around_medium">
        <template for:each={answers.data} for:item='answer'>
            <p key={answer.answerId}>
                <lightning-input class="slds-m-left_medium" label={answer.answerName} name="radios" type="radio" ></lightning-input>
            </p>
        </template>
    </lightning-card>
</template>

Answer.js

import { LightningElement, wire } from 'lwc';
import getWrapperClassList from '@salesforce/apex/ControllerClass.getWrapperClassList'; 

export default class IBAnswer extends LightningElement {
   @wire(getWrapperClassList)
   answers
}

The current code returns multiple questions related to each options i.e. One question which has 4 answers will return 4 questions for one answer each.

2
  • Can you please add your javascript code? It seems like it's a wired call.. Commented Dec 31, 2021 at 6:28
  • @SachinHooda added the JS
    – code234
    Commented Dec 31, 2021 at 6:34

2 Answers 2

1

You don't need the wrapper class as you leverage the Ques-Ans relationship.

Change the query as below so you use only one query. so the apex function looks like this. Be mindful to change the relationship name in the SOQL query. I assumed it to be Ans__r.

@AuraEnabled(cacheable = true)
public static List<Ques__c> getQuestionAnswers() {
    return [
        SELECT Id, 
        Content__c, 
        (SELECT 
            Id, 
            Name, 
            Ques__c,
        FROM Ans__r) 
        FROM Ques__c
    ];
}

Now make the below changes to HTML.

<template>
    <lightning-card class="slds-m-around_medium">
        <template for:each={questionAnswers.data} for:item='ques'>
            <template for:each={ques.Ans__r} for:item='answer'>
                <p key={answer.Id}>
                    <lightning-input class="slds-m-left_medium" label={answer.answerName} name="radios" type="radio" ></lightning-input>
                </p>
            </template>
        </template>
    </lightning-card>
</template>

JS.

@wire(getQuestionAnswers)
questionAnswers;

Now you can also use two different components for Question & answer to display them individually. You can do all of this code in another parent component and then you just need to pass down the question and answer records into them.

1
  • +1 for typing speed. Commented Dec 31, 2021 at 10:22
0

As Rahul mentioned already you don't need a wrapper to show such parent-child records if you modify how you query the data. This is much similar to Rahul's answer.

Question.html

<template>
    <lightning-card>
        <div if:true={error}>{error}</div>
        <div if:false={error} if:true={data}>
            <template for:each={data} for:item="question">
                <lightning-accordion allow-multiple-sections-open title={question.Name} key={question.Id}>
                    <template for:each={question.Answers__r} for:item="answer" for:index="ansIndex">
                        <lightning-accordion-section key={answer.Id} title={question.Name} label={question.Text__c}>{answer.Text__c}</lightning-accordion-section>
                    </template>
                </lightning-accordion>
            </template>
        </div>
    </lightning-card>
</template>

Question.js

import { LightningElement, wire } from 'lwc';
import getQuestionsAndRelatedAnswers from '@salesforce/apex/QuestionsController.getQuestionsAndRelatedAnswers';

const DEFAULT_ANSWER = { Text__c: 'No Answers found for this question' };
export default class Question extends LightningElement {

    error = '';
    data = [];

    @wire(getQuestionsAndRelatedAnswers)
    wiredQuestions({ error, data }){
        if(error){
            this.error = JSON.stringify(error);
        } else if(data){
            this.data = data.map(item => ({...item, Answers__r: item.Answers__r?.length ? item.Answers__r : [ DEFAULT_ANSWER ] }), []);
        }
    }
}

QuestionsController.cls

public with sharing class QuestionsController {
    @AuraEnabled(cacheable=true)
    public static Question__c[] getQuestionsAndRelatedAnswers(){
        return [
            SELECT Id, Name, Text__c, (SELECT Id, Name, Text__c FROM Answers__r) FROM Question__c
        ];
    }
}

I added some additional logic to show No answers found for this questions for Questions not having any answer. This is how it appears, enter image description here

There were other few issues I want to point.

  • You should name your classed and method something meaningful.
  • Both of your components were entirely similar they do even have the same controllers.

Here is a small playground example that I build based on similar data.

You must log in to answer this question.

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