0

I'm facing a problem from passing a list of custom objects from the Controller of my Aura Componentk, to Apex. Apex does not receive the parameters, It seems to be "normal", I read it's better to stringify the list, pass it from the js Controller to Apex in String, and deserialize it in apex.

In order to simplify, I use a snippet of JSON : I'm trying something like :

    String uploadedFilesJSON = '[{"name":"5 CE.pdf","documentId":"0693N0000022M6wQAE","contentVersionId":"0683N0000022edeQAA","contentBodyId":"05T3N000006XadyUAC","mimeType":"application/pdf"}]';
    List<ContentDocumentLink> cdtListFromJSON = (List<ContentDocumentLink>) JSON.deserialize(uploadedFilesJSON , List<ContentDocumentLink>.class);
    System.debug('\n\ncdtListFromJSON : \n'+cdtListFromJSON+'\n');

There is no bug but I got only empty fields ->

enter image description here

I'm also trying with regular objects, list of accounts, and it seems to work better :

    String JSONAccounts = '[ { "attributes": { "type": "Account", "url": "/services/data/v51.0/sobjects/Account/0013N00000sOmq5QAC" }, "Id": "0013N00000sOmq5QAC", "IsDeleted": false, "MasterRecordId": null, "Name": "LA_CITY", "LastName": null, "FirstName": null, "RecordTypeId": "01209000001QrZAAA0" }, { "attributes": { "type": "Account", "url": "/services/data/v51.0/sobjects/Account/0013N00000s68AdQAI" }, "Id": "0013N00000s68AdQAI", "IsDeleted": false, "MasterRecordId": null, "Name": "Shai Haddad", "LastName": "Shai Haddad", "FirstName": null, "RecordTypeId": "01209000001Qs86AAC" }, { "attributes": { "type": "Account", "url": "/services/data/v51.0/sobjects/Account/0013N00000sOGvQQAW" }, "Id": "0013N00000sOGvQQAW", "IsDeleted": false, "MasterRecordId": null, "Name": "Jean Valjean", "LastName": "Jean Valjean", "FirstName": null, "RecordTypeId": "01209000001Qs86AAC" }]';
    List <Account> accList = (List <Account>) JSON.deserialize(JSONAccounts, List <Account>.class);
    System.debug('\n\naccListFromJSON : \n'+accList+'\n');

I got this as output :

19:29:07:000 USER_DEBUG

(Account:{IsDeleted=false, FirstName=null, RecordTypeId=01209000001QrZAAA0, Id=0013N00000sOmq5QAC, LastName=null, MasterRecordId=null,Name=LA_CITY},

Account:{IsDeleted=false, FirstName=null, RecordTypeId=01209000001Qs86AAC, Id=0013N00000s68AdQAI, LastName=Shai Haddad, MasterRecordId=null, Name=Shai Haddad},

Account:{IsDeleted=false, FirstName=null, RecordTypeId=01209000001Qs86AAC, Id=0013N00000sOGvQQAW, LastName=Jean Valjean, MasterRecordId=null, Name=Jean Valjean})

Nb : I've read this, so I wanned to inspire my code from it How to pass sobject list to apex from lightning?

EDIT : basically in my component :

<aura:attribute name="downloadedFiles" type="ContentDocumentLink[]" />

and

<lightning:fileUpload label=""
                      name="fileUploader"
                      multiple="{!v.multiple}"
                      accept="{!v.fileType}"
                      recordId="{!v.recordId}"                                              
                      fileFieldName="Guest_Record_fileupload__c"
                      fileFieldValue="{!v.encryptedToken}"                        
                      onuploadfinished="{!c.uploadFinished}" />

In its controller :

    uploadFinished : function(component, event, helper) {  
            var uploadedFiles = event.getParam("files");
            component.set("v.downloadedFiles", uploadedFiles);
            
            uploadedFiles.forEach((file) => console.log('uploadFinished file : '+file));
            helper.linkFileToMedicalDoc(component, uploadedFiles);
            console.log('\n\nhelper UploadFinished -> FINISH');
       }

The helper method :

    linkFileToMedicalDoc : function(component, uploadedFiles) {

        console.log('\n\nuploadedFiles : \n\n'+JSON.stringify(uploadedFiles));
        console.log('\n\nlinkFileToMedicalDoc() -- component.get("v.downloadedFiles") : \n\n'+JSON.stringify(component.get("v.downloadedFiles")));

        var uploadedFilesAsString = JSON.stringify(uploadedFiles);

        var action = component.get("c.linkFileToMedicalDoc");  
        action.setParams({  
            "recordId":component.get("v.recordId"),
            "uploadedFiles": uploadedFilesAsString //$A.util.JSON.encode(uploadedFiles) //.encode(uploadedFiles) 
        });

        action.setCallback(this,function(response){  
            var state = response.getState();  
            if(state=='SUCCESS'){  
                // var result = response.getReturnValue();
                // console.log('Helper : linkFileToMedicalDoc() - uploadedDocs : '+JSON.stringify(result));
            }  
        });  
        console.log('Helper : linkFileToMedicalDoc() - FINISH');
        $A.enqueueAction(action);
    }

And the APEX (only the beginning, the rest won't whatever) :

    @AuraEnabled
        public static void linkFileToMedicalDoc(Id recordId, String uploadedFiles)  { 
            System.System.debug('\n\nVFC02_UploadDoc -> linkFileToMedicalDoc() - recordId :'
                +recordId+'\n');
            
            // deserialiser le JSON :
            // System.debug('uploadedFiles : \n\n'+uploadedFiles);
            // List<ContentDocumentLink> cdtListFromJSON = (List<ContentDocumentLink>)JSON.deserialize(uploadedFiles, List<ContentDocumentLink>.class); //convertJSONToListOfSObject(uploadedFiles);
    
    etc...
    }

Thanks for your help, And note that at first, I was only trying to send the newly uploaded files (via component.get('v.uploadedDocuments')) as a List of ContentDocumentLink but my Apex wasn't able to get it.. So I tryed with JSON and passing strings, as I read was a solution. I'll try to adapt my code in order to get the right fields. I'm obviously missing something ..

Nb : if you need the debugs I can provide it, but basically it's ok in console before sending it to APEX, but Apex receive an empty list.

1
  • 4
    what does your apex method accept as a param? kinda hard to help you spot why its not working without seeing the relevant code.
    – glls
    Feb 14, 2022 at 19:10

1 Answer 1

1

You have the wrong object; your fields don't match up, so that's why it appears empty. A ContentDocumentLink inside a list should look like this:

    [
      {
        "attributes": {
          "type": "ContentDocumentLink",
          "url": "/services/data/v54.0/sobjects/ContentDocumentLink/06A1T00000I0CYJUA3"
        },
        "Id": "06A1T00000I0CYJUA3",
        "LinkedEntityId": "00550000000wTdSAAU",
        "ContentDocumentId": "0691T00000D6EELQA3",
        "IsDeleted": false,
        "SystemModstamp": "2021-05-12T02:45:40.000+0000",
        "ShareType": "I",
        "Visibility": "AllUsers"
      }
    ]

Make sure you're using the correct object to deserialize to.

Also, note that the fields should be considered case sensitive, and the attributes property should be present, and should be the first property of the JSON object. Failure to adhere to the format strictly may cause random failures.

Also, as a side note, it is rarely ever necessary to use JSON in this way; LWC and Aura are smart enough to encode objects as JSON for you, so, technically, you're double-encoding when you do manual encoding yourself.

    @AuraEnabled public static SomeReturnType someMethod(List<ContentDocumentLink> records) {
      ...
    }

...

    // let records = [{ attributes: { type: "ContentDocumentLink", url: ... }, ...]
    let result = await someMethod({records})

Using lightning:fileUpload gives you the basic details you need, but they are not ContentDocumentLink objects, they are just a generic client-side format.

If you want them to be in the correct format, you'll want to use Array.prototype.map on the client side first:

    ({
      linkFileToMedicalDoc: function (component, uploadedFiles) {
        const links = uploadedFiles.map((file) => ({
          attributes: { type: "ContentDocumentLink" },
          ContentDocumentId: file.documentId,
          LinkedEntityId: component.get("v.recordId"),
          ShareType: "I",
          Visibility: "AllUsers",
        }));
        const action = component.get("c.linkFileToMedicalDoc");
        action.setParams({ links });
        action.setCallback(this, function (result) {
          console.log(result); // do something here
        });
        $A.enqueueAction(action);
      },
    })

Which you can then handle on the server:

    @AuraEnabled
    public static void linkFileToMedicalDoc(ContentDocumentLink[] links) { 

3
  • Thanks for answering, I'll try that : // let records = [{ attributes: { type: "ContentDocumentLink", url: ... }, ...] let result = await someMethod({records}) (+ I added my code). Feb 15, 2022 at 9:24
  • 1
    @AlexisMASSON Oh, you're using lightning:fileUpload. What you're asking for makes a lot more sense now. You can transform the data using Array.prototype.map, which I've edited in to this answer for you.
    – sfdcfox
    Feb 15, 2022 at 12:11
  • Owh.. It was clear in my head but I didn't mention it, my bad !! Thanks, I'll try it then (can't do it now, it's a shame but have much more urgent stuff to fix, but I'll let you know !) Again thanks for your concern !! Feb 15, 2022 at 12:52

You must log in to answer this question.

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