Skip to content

15. Recording the Answers in the Questionnaire_Answer component (Section 5)

barryhughes1 edited this page Nov 3, 2017 · 9 revisions

At this stage, Questions are being displayed to the user with inputs to answer - but these inputs are linked to local attributes only. These inputs must now be aligned with a 'QUestionnaire_Answer__c' record.

  1. In the 'Questionnaire_Answer__c' component, add a force:recordData component for a Questionnaire_Question__c along with its necessary attributes in the 'Data Service Components' section of the markup.
    <!-- 5. Data Service Components -->  
    ....[Questionnaire_Question__c record attributes]....

    <aura:attribute name="answer" 
                    type="Questionnaire_Answer__c" 
                    description="Questionnaire Answer Record object from Data Service (targetRecord)"/>
    <aura:attribute name="answerFields" 
                    type="Questionnaire_Answer__c" 
                    description="Questionnaire Answer Record object from Data Service (targetFields)"/>
    <aura:attribute name="answerRecordError" 
                    type="String" 
                    description="Question Record Errors from Data Service (targetError)"/>
    <force:recordData aura:id="answerRecordLoader"
                    recordId="{!v.questionObj.answerID}"
                    fields="Id,Name,Agree_with_Question__c,QuestionnaireQuestion__c,Questionnaire_Returned__c,Comments__c"
                    targetFields="{!v.answerFields}"
                    targetRecord="{!v.answer}"
                    targetError="{!v.answerRecordError}"
                    recordUpdated="{!c.handleAnswerRecord_LDS}"
                    mode="EDIT"
                    />
  1. The javascript function to handle the force:recordData component must be added to the controller of the 'Questionnaire_Answer__c' component.
    // Handle Answer (Data Service) function
    handleAnswerRecord_LDS : function(component, event, helper) {
        var eventParams = event.getParams();
        var objName = "Answer";
        // Using general helper method from c:utilityFunctions
        helper.handle_LDS_cmp(component, helper, eventParams, objName);        
    } 
  1. Now change the lightning:radiogroup input to use the answerFields attribute. We will use an onblur event to make saves to the answer record.
                         <lightning:radioGroup aura:id="mygroup"
                            name="{!v.questionFields.Name}"
                            label="{!v.questionFields.Name}"
                            type="radio"
                            options="{! v.options }"
                            value="{! v.answerFields.Agree_with_Question__c }"
                            onchange="{! c.handleAnswerChange }" />
  1. Change the lightning:input for 'comments' to use the answerFields attribute. We will use an onblur event to make saves to the answer record. Note that both inputs use the same Save function.
                        <lightning:input name="comments" value="{!v.answerFields.Comments__c}"
                                        placeholder="Please add any further comments"
                                        onblur="{!c.handleAnswerChange}" />
  1. Add the answerRecordError attribute to the display in case we get an error with the answer recordData component.
        <aura:if isTrue="{!not(empty(v.answerRecordError))}">
            <ui:message title="Error" severity="error" closable="true">
                {!v.answerRecordError}
            </ui:message>
        </aura:if>        
  1. Add the javascript function to the controller to make updates to the Questionnaire_Answer record.
    handleAnswerChange: function (component, event, helper) {
	// Need to save a new (or update an existing)
	// answer with the selection
	// and the comments when change
        console.log('handleAnswerChange');
        helper.handleSaveAnswerRecord(component,helper);
    }
  1. The save javascript function in the controller of the 'Questionnaire_Component' will use a helper function to make the save.
    handleSaveAnswerRecord: function(component,helper) {

        var answerRec = component.get("v.answerFields"); 

        // Developer Note on weird behaviour found with radio buttons
        // It seems that when changing the value of the radio button group
        // LDS is interpreting the new value as an array (??)
        // which means the save of the record will fail
        // So, I am reverting it to  string here
        var jsonAgree = JSON.stringify(answerRec.Agree_with_Question__c);
        if(jsonAgree.substring(0,1) == "[")
            answerRec.Agree_with_Question__c = answerRec.Agree_with_Question__c[0];            

        // Now for the rest of the fields - re-affirming lookup field values.        
        var questionRec = component.get("v.questionObj");
        answerRec.QuestionnaireQuestion__c = questionRec.questionID;
        answerRec.Questionnaire_Returned__c = component.get("v.returnId");

        // Call the saveRecord method available in the force:recordData base component.
        component.find("answerRecordLoader").saveRecord($A.getCallback(function(saveResult) {
            // NOTE: If you want a specific behavior(an action or UI behavior) when this action is successful 
            // then handle that in a callback (generic logic when record is changed should be handled in recordUpdated event handler)
            if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
                // handle component related logic in event handler
                console.log('save successful');
                console.log(JSON.stringify(saveResult));
                var questionObj = component.get("v.questionObj");
                console.log('==> ' + questionObj.answerID);
                // When creating a new Answer record, (the
                // questionObj.answerID will be undefined),
                // we must set the ID to the saveResult's recordId
                // so that the 'recordUpdated' handler function
                // will fire.
                if(!questionObj.answerID) {
                    questionObj.answerID = saveResult.recordId;
                    console.log('==> ' + questionObj.answerID);
                    // The 'recordUpdated' function is not going to fire here
                    // so we must do a toast now (other toasts are in the handler)
                    helper.showMessageAsToast("success", "The Answer was successfully saved.", "dismissible");    
                }
            } else if (saveResult.state === "INCOMPLETE") {
                console.log("User is offline, device doesn't support drafts.");
            } else if (saveResult.state === "ERROR") {
                console.log('Problem saving record, error: ' + JSON.stringify(saveResult.error));
                helper.showMessageAsToast("error", 'Problem saving record, error: ' + JSON.stringify(saveResult.error), "dismissible");
            } else {
                console.log('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error));
//                alert('Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error));
                helper.showMessageAsToast("error", 'Unknown problem, state: ' + saveResult.state + ', error: ' + JSON.stringify(saveResult.error), "dismissible");
            }
        }));
    }
  1. The save javascript functionality has been written, but it will fail if no 'Questionnaire_answer__c' record exists and initiated in the force:recordData component. In the initialisation of the component we must check for an existing Answer record, if one doesn't yet exist, it must be initialized using the force:recordData's getNewRecord method.

  2. Add a doInit function to the 'Questionnaire_Answer' component to check for an answerID in the questionObj object.

    doInit: function(component,event,helper) {
        // helper.detectUtilityBar(component);
        var obj = component.get("v.questionObj");

        // Detect if an Answer has been created for the Question
        // for the user already
        // IF NOT we must initialise the answer LDS component
        var answerRec = component.get("v.questionObj").answerID;
        if(!answerRec) {
            helper.initAnswerRecord(component, helper);
        }

    },
  1. Add a doInit handler to the 'Questionnaire_Answer' component
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
  1. Add a method to the helper to initialize a Questionnaire_Answer__c record using the getNewRecord function.
    initAnswerRecord: function(component, helper) {
        // Prepare a new record from template
        component.find("answerRecordLoader").getNewRecord(
            "Questionnaire_Answer__c", // sObject type (objectApiName)
            null,      // recordTypeId
            false,     // skip cache?
            $A.getCallback(function() {
                var rec = component.get("v.answer");
                var error = component.get("v.answerRecordError");
                if(error || (rec === null)) {
                    console.log("Error initializing record template: " + error);
                    return;
                }
                console.log("Record template initialized: " + rec.sobjectType);
            })
        );
    }       
  1. At this stage most of the code is there to save a Questionnaire_Answer__c record and editing an existing Answer record will work fine. Questionnaire_Answer__c records can also be created where a 'Questionnaire_Returned__c' record has been created for the Questionnaire by the user.

However, there will be a problem saving a new answer record if no parent 'Questionnaire_Returned__c' exists. Since it has a Master-Detail relationship with Questionnaire_Returned__c, a new Questionnaire_Answer__c record requires a parent Questionnaire_Returned__c record be created before it can be successfully saved.

In the next section the creation of the 'Questionnaire_Returned__c' record will be added.