15. Recording the Answers in the Questionnaire_Answer component (Section 5)
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.
- 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"
/>
- 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);
}
- 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 }" />
- 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}" />
- 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>
- 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);
}
- 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");
}
}));
}
-
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.
-
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);
}
},
- Add a doInit handler to the 'Questionnaire_Answer' component
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
- 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);
})
);
}
- 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.