0

I'm just getting to grips with Apex and trying to get an API working with Open Weather Map API. Currently, the API Trigger I use only runs on record creation and it works great. But, I would also like it to run when the record is updated too.

How do I perform an update to the record when changed?

Here is the Trigger:-

trigger Weather on Weather__c (before update, after insert) {

if (Trigger.isAfter) {
    // create list to hold the Weather Record ID
    List<String> recordId = new List<String>();

    // create new Weather to pull the Weather ID
    for (Weather__c Weth : Trigger.new) {

        // new instance of the Weather is set to a
        Weather__c w = new Weather__c();

        // set the Id to the Id of the new Weather
        w.Id = Weth.Id;

        // add the Weather ID to the recordId List
        recordId.add(w.Id);

        // call the processRecords method and pass the recordId List
        WeatherHandler.ManageRecords(recordId); 
    }
}

if (Trigger.isBefore) {
    //for(Weather__c a : Trigger.New) {
    //a.Description__c = Descr;
    List<String> recordId = new List<String>();
    WeatherHandler.ManageRecordsBefore(recordId);
}   
}

And here is the Apex:-

 public class WeatherHandler {
    // create empty string variable
    static String retVal = null;
    static String Descr = null;
    static String clouds = null;
    static String name = null;


    @future(callout=true)
    public static void ManageRecords(List<ID> recordId) {

        // external callout to the api
        Http http=new Http();
        HttpRequest request= new HttpRequest();
        request.setEndPoint('https://api.openweathermap.org/data/2.5/weather?q=Ulverston&APPID=6a4199d8698bb67cc604e3fb8082599d');
        request.setMethod('GET');
        HttpResponse response=http.send(request);
        response = http.send(request);

        // if callout is successful (code: 200)
        if (response.getStatusCode() == 200) {

            // parse the JSON
            Map<String, Object> results = (Map<String, Object>) JSON.deserializeUntyped(response.getBody());

            // change the api value results to a string and assign to string variable
            retVal = string.valueof(results.get('weather'));
            Descr = string.valueof(results.get('base'));
            clouds = string.valueof(results.get('clouds'));
            name = string.valueof(results.get('name'));

            // get record based on ID; can also put SOQL in place of acct in for loop
            List<Weather__c> Weth = [SELECT Name
                                 FROM Weather__c
                                 WHERE Id IN :recordId];

            // for all of accounts that have the Account ID recordId
            for (Weather__c W : Weth) {

                // set the Ticker Start field to the external callout value for 'retVal'
                W.Clouds__c = clouds;
                W.Description__c = Descr;
                W.Weather__c = retVal;
                W.Weather__c = retVal;
                W.name = name;

                // update the record
                update W;
            }
        }
    }

    public static void ManageRecordsBefore(List<ID> recordId) {
    List<Weather__c> Weth2 = [SELECT Name FROM Weather__c WHERE Id IN :recordId];
        for (Weather__c W2 : Weth2) {
                W2.name = 'Descr';
                update W2;
            }
    }   
}

From my understanding, it should be done as a 'Before Update' in this area but adding this in has no effect and doesn't update the fields on edit:-

    if (Trigger.isBefore) {   
    //for(Weather__c a : Trigger.New) {
    //a.Description__c = Descr;
    List<String> recordId = new List<String>();
    WeatherHandler.ManageRecordsBefore(recordId);
}   
        }

This doesn't update the fields on the Weather record as intended. I've tried different methods but I lack the understanding of how it should be formatted on a "before update" trigger.

Any help/code examples will be greatly appreciated thank you.

Fields I would Like to Update:- Fields To Update

  • When you say it "doesn't work", what do you mean? Have you put in any System.debug statements and checked the logs to confirm where the code actual goes or does not go? – Kris Goncalves Oct 29 '19 at 16:50
  • Sorry, I should have been more clear. It doesn't update the fields on the Weather record. I'll update the question and show the fields that I aim to update. @KrisGoncalves – Daniel Bleasdale Oct 29 '19 at 16:54
  • 1
    @DanielBleasdale, remember that if you are instantiating a class on a Before Update you don't need to use DML operations because the before update will take care of it. – Carlos Naranjo Oct 29 '19 at 17:49
  • But how would I pass the variables generated from the future callout on the "After Insert" into the "Before Update" ? Do I need to make a second callout specifically for the "Before Update"? Cheers – Daniel Bleasdale Oct 31 '19 at 9:35
1

On this line

if (Trigger.isBefore) {   
//for(Weather__c a : Trigger.New) {
//a.Description__c = Descr;
List<String> recordId = new List<String>();
WeatherHandler.ManageRecordsBefore(recordId);

You are instantiating a list of strings, but not adding any values to it, so the list is null, and I can only assume this is not what you want to do. The update below should help.

if (Trigger.isBefore) {   
     //for(Weather__c a : Trigger.New) {
     //a.Description__c = Descr;
     List<Id> recordId = new List<Id>();
     recordId.addAll(trigger.oldMap.keySet());
     List<String> recordIdString= new List<String>((list<String>) recordId);
     WeatherHandler.ManageRecordsBefore(recordIdString);
}

I wanted to explain the update line by line so you could follow what the changes are and what they are doing:

This line will instantiate a null List of Ids just like your previous code (except this will be a data type of Id where your original code was to instantiate a List of Strings)

List<Id> recordId = new List<Id>();

Then we are going to add the Id's of the records involved in your trigger to the newly created Id List from the trigger oldmap keyset.

recordId.addAll(trigger.oldMap.keySet());

Lastly, we are then going to create a new List of Strings and add the List of Ids casting a type of String

List<String> recordIdString= new List<String>((list<String>) recordId);

When you make this update, without any other code changes, you will more than likely get an error, because as Carlos pointed out you can't make a DML operation during a Before trigger, so you should probably drop the

update W2;

from your ManageRecordsBefore method.

Based upon your line of questioning, I don't think this is going to solve everything for you as your ManageRecordsBefore method is just updating the Name field to "Descr" and I get the feeling that's not what you want to do, but hopefully knowing how to pass a list of strings to your class can help you in your process of figuring this out.

|improve this answer|||||
  • That's great thank you, I'll give it a try, really appreciate you taking the time to explain the workings and making it understandable for me cheers. – Daniel Bleasdale Nov 1 '19 at 10:19
  • I updated the trigger as follows "if (Trigger.isBefore) { List<Id> recordId = new List<Id>(); recordId.addAll(trigger.oldMap.keySet()); List<String> recordIdString= new List<String>((list<String>) recordId); WeatherHandler.ManageRecordsBefore(recordIdString); }" and I removed the "update W2;" from the class but it isnt updating on edit still, ill juggle around with it cheers and see if I get it working. – Daniel Bleasdale Nov 1 '19 at 15:18

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.