4

I am looking to make a lightning component to insert my Transaction__c object records against all relevant Contracts pulled back requiring action. As it stands I am returning all of relevant contracts/Assets that need transactions inserting for that month looking like so:

enter image description here

I am a bit at a loss though on how to actually insert using the component, specifically when the input field we are looking to create the object could be different month to month. My current code looks like so.

AddTransactionsController

public class AddTransactionsController {
 @AuraEnabled public static list <Contract> fetchContract() {
   Date d = date.today();
   String dS; 
   dS = d.Month() + '/' + d.year();
   List <Contract> lstOfCon = [
      SELECT 
         id, contractnumber, merchant_account__c, status,
         (SELECT id, name from assets__r WHERE name='Sagepay' OR name='Fidelipay'),
         (SELECT id, name, related_month__c, contract__c, related_asset__c FROM transactions__r)
      FROM contract 
      WHERE 
         Id Not IN (
            SELECT contract__c FROM Transaction__c WHERE related_month__c=:dS
         )
         AND status='Activated' 
         AND RecordType.developername='Gateway_Contract'
   ];
   return lstOfCon;
 }   
}

As for the component itself:

AddTransactionComponent

<aura:component controller="AddTransactionsController" implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
   <aura:attribute name="ListOfContract" type="Contract[]"/>
   <ul>
      <aura:iteration items="{!v.ListOfContract}" var="con" indexVar="index">
         <li type="dice">Contract Number : {!con.ContractNumber}</li>
         <ul>
            <aura:iteration items="{!con.Assets__r}" var="asset" indexVar="index">
               <li>Asset {!index + 1} Name : {!asset.Name}</li>
                <ui:inputnumber aura:id="num" required="true" class="field"></ui:inputnumber>
            </aura:iteration>
         </ul>
         <hr/>
      </aura:iteration>
   </ul>
    <lightning:button label="submit" onclick="{!c.submit}"></lightning:button>
</aura:component>

AddTransactionsController

({
    doInit: function(component, event, helper) {
      //call apex class method
      var action = component.get('c.fetchContract');
      action.setCallback(this, function(response) {
       //store state of response
       var state = response.getState();
       if (state === "SUCCESS") {
        //set response value in ListOfAccount attribute on component.
           console.log('response : ' + response.getReturnValue());
        component.set('v.ListOfContract', response.getReturnValue());
       }
      });
      $A.enqueueAction(action);
     },

    submit: function(component, event, helper) {

    },
})

I understand this functionality will have to be handled on Submit in conjunction with the apex controller but my real question is how do I determine on insert which contract / asset each field in the interation applies too.

Thanks

  • If what you want is to insert for each contract a new Transaction__c record, based on the input data - why do you iterate also on the asset and inside that add the input? – Itai Shmida Aug 16 '17 at 7:13
  • Because on a very rare occasion there may be more than on asset therefore 2 transactions will be added one for each asset linked to the same contract – Nebbyyy Aug 16 '17 at 8:39
  • But from the SELECT statement, your data model does not seem to work this way... – Itai Shmida Aug 16 '17 at 8:40
  • How do you think it should look asset over contract? – Nebbyyy Aug 16 '17 at 8:54
  • I am not really sure - from your SELECT I see you have on your Transaction__c object a lookup field to Contract not to asset. What exactly are you trying to accomplish? – Itai Shmida Aug 16 '17 at 9:01
4
+50

A conceptual approach could be

  • store the data you need as custom data-attributes in the <li>
  • collect the data you need into a JavaScript object (I use jquery for DOM-operations like this - others here will crucify me for that)
  • serialize the object into a JSON string
  • pass the JSON string to another Apex method using an action
  • in Apex deserialize the JSON string and loop through the structure
  • dynamically create a list of type Transactions__c[]
  • insert this list

I don't have your datamodel in my Orgs, therefore I can't save the following code (hence it might contain typos and errors). This said, it could look something like this:

Prerequisites

  • download and create a Static Resource named jquery_js first

Markup

It's basically your code plus two lines:

  • load jquery using ltng-require
  • add a classname and auxiliary data-attributes to the <li>

Here the component

<aura:component controller="AddTransactionsController" implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global">
   <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
   <aura:attribute name="ListOfContract" type="Contract[]"/>
   <ltng:require afterScriptsLoaded="{!c.afterScriptsLoaded}"
        scripts="{!join(','
            ,$Resource.jquery_js
        )}"
    />
   <ul>
      <aura:iteration items="{!v.ListOfContract}" var="con" indexVar="index">
         <li type="dice">Contract Number : {!con.ContractNumber}</li>
         <ul>
            <aura:iteration items="{!con.Assets__r}" var="asset" indexVar="index">
                <li class="myMissingTransactions" 
                    data-assetid="{!asset.id}" 
                    data-contractid="{!con.id}" 
                >
                     Asset {!index + 1} Name : {!asset.Name}
                </li>
                <ui:inputnumber aura:id="num" required="true" class="field"></ui:inputnumber>
            </aura:iteration>
         </ul>
         <hr/>
      </aura:iteration>
   </ul>
   <lightning:button label="submit" onclick="{!c.submit}"></lightning:button>
</aura:component>

JS Controller

  • select all li's where class=myMissingTransactions
  • create a new object, pupulate fields with the data you stored in the data-attributes above
  • use an action to send the a serialized version of the data to Apex

Note: I've tried to do this with the plain and unserialized data first, but ran into several issues. Serializing helped me to avoid these issues. I can not exactly remember the details.

submit: function(cmp, evt, hlp) {
    newTransactions = [];
    $('.myMissingTransactions').each(function(){
        newTransactions.push({ 
            Asset__r      : $(this).attr('assetid'),
            Contract__c   : $(this).attr('contractid'),
            // more fields here
        })
    });
    var action = component.get('c.executeInsert');
    action.setParams( { newTransactionsJSON : JSON.stringify( newTransactions ) } );
    action.setCallback(this, function(response) {});
    $A.enqueueAction(action);               
},

Apex Controller

  • Here all the fuzz is about reverting the serialization on the fly
  • please check if you either need to transfer more fields or need to populate other stuff on Transaction__c
  • via JSON you can transfer almost anything from JS to Apex - it's just a matter of correct deserialization and typecasting

Note: this could be also done using an inner class in a more typed manner - but I don't like it typed. Try for yourself what works best for you

@AuraEnabled public static executeInsert( String newTransactionsJSON ) {
    Transaction__c[] transactions = new Transaction__c[]{};
    List<Object> newRawTransactions = (List<Object>) JSON.deserializeUntyped( newTransactionsJSON );
    for(Object newRawTransaction : newRawTransactions) {
        transactions.add( new Transaction__c(
              Asset__r     = (Id) (Map<String,Object)newRawTransaction.get('Asset__r')
            , Contract__r  = (Id) (Map<String,Object)newRawTransaction.get('Contract__r')
            // more fields here
        ));
    }
    insert transactions;
}
  • So this is almost exactly what i am trying to do , but i am new to sales force (lucky me) and I am not sure what the apex controller is in my case. I have an aura definition bundle that I am working with and I have the visualfoce component.cmp, the helper.js and the controller.js. In my helper.js file I wish to make a call to an apex function just like this so i can insert a record. but i cannot find a apex controller for this. any help would be great, Thanks. – azyth Sep 4 '18 at 18:04
  • I figured out my own question: controller="AddTransactionsController" references an " Apex Class" file that has functions can then be called via the specified method. – azyth Sep 4 '18 at 18:33
  • and your component.cmp is NO visualforce but just "markup" ;-) – Uwe Heim Sep 5 '18 at 13:34

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.