model.save() not working (my face is all screwed up and 'm gritting my teeth >:( )


Pat can you post your whole snippet, it looks like a real doozie. I have a theory that you might be running into issues with asynchrosity and callbacks. Because a save takes a second or 2 to communicate with the server, you can run into issues when your snippet keeps on going and doesn’t wait for your save to finish. You can pass a function into the save function to force it to run after the save finishes.

function myFunctionThatWillHappenAfterTheSave(){<br>&nbsp; &nbsp; alert('Hello World');<br>}<br>//the function will not be run until the save finishes...<br>myModel.save(myFunctionThatWillHappenAfterTheSave());

Video uploading now. Here’s the code.



var params = arguments[0], $ = skuid.$; var jrModel = skuid.$M('JobReport'), jrRow = jrModel.getFirstRow(), // date objects for report start &amp; end dates jrStartDate = skuid.time.parseSFDate(jrRow.RECON__Report_Start_Date__c), jrEndDate = skuid.time.parseSFDate(jrRow.RECON__Report_End_Date__c); // date strings for report start &amp; end dates jrStartDateStr = jrStartDate.toISOString(), jrEndDateStr = jrEndDate.toISOString(); // ref ids for weather logs jrAddress = jrRow.RECON__Job__r.RECON__AddressRef__c; flModel = skuid.$M('FirstJobLocation'), flRow = flModel.getFirstRow(), flId = flRow.Id; // Get WeatherLogs and set it's conditions to match job selections. job, start date and end date var wlModel = skuid.$M('WeatherLogs'), wlModelJobCond = wlModel.getConditionByName('Job'), wlModelStartCond = wlModel.getConditionByName('StartDate'), wlModelEndCond = wlModel.getConditionByName('EndDate'); // set conditions wlModel.setCondition(wlModelJobCond,jrRow.Id); wlModel.setCondition(wlModelStartCond,jrStartDate); wlModel.setCondition(wlModelEndCond,jrEndDate); // activate conditions wlModel.activateCondition(wlModelJobCond); wlModel.activateCondition(wlModelStartCond); wlModel.activateCondition(wlModelEndCond); // query model wlModel.updateData(); // deactivate conditions wlModel.deactivateCondition(wlModelJobCond); wlModel.deactivateCondition(wlModelStartCond); wlModel.deactivateCondition(wlModelEndCond); var wldatearray = []; // Gather Dates from wlModel in array so they can be searched for in the following while loop for (var datakey in wlModel.data) { var dataobj = wlModel.data[datakey]; for (var prop in dataobj){ if(dataobj.hasOwnProperty(prop) &amp;&amp; prop == 'RECON__Forecast_Date__c' ){ wldatearray[wldatearray.length] = skuid.time.parseSFDate(dataobj[prop]).toISOString(); // console.log(wldatearray); } } } function getWeatherReport(wrdate){ // base url &amp; url parameters from job. item url parameter to come from start/end date loop // forecast.io URL format: // https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME var url = 'https://api.forecast.io/forecast/', apiKey = '27b81979ec35eddcc6b95323b9546d78', latitude = jrRow.RECON__Job__r.RECON__AddressRef__r.RECON__Geocode__Latitude__s, longitude = jrRow.RECON__Job__r.RECON__AddressRef__r.RECON__Geocode__Longitude__s; //var forecastdate = wlRow.RECON__Forecast_Date__c.substring(11,0).concat('12:00:00'); var forecastdate = wrdate.toISOString().substring(11,0).concat('12:00:00'); var conditions=[ {field: 'RECON__Forecast_Date__c', value: skuid.time.getSFDate(wrdate)} ]; /* waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu sunriseTime = {RECON__Sunrise_Time__c: objJSON.daily.data[0].sunriseTime }, sunsetTime = {RECON__Sunset_Time__c: objJSON.daily.data[0].sunsetTime }, time = {RECON__Weather_Report_Time__c: objJSON.daily.data[0].time }, precipIntensityMaxTime = {RECON__Precip_Intensity_Max_Time__c: objJSON.daily.data[0].precipIntensityMaxTime }, temperatureMinTime = { RECON__Temperature_Min_Time_Time__c: temperatureMinTimeCalc }, temperatureMaxTime = {RECON__Temperature_Max_Time__c: objJSON.daily.data[0].temperatureMaxTime }, */ function waitforsave(){ console.lg('modelsaved'); } wlModel.createRow({ additionalConditions: conditions}); wlModel.save(waitforsave); getForecast(); function getForecast(){ /* waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu jsdate = skuid.time.parseSFDateTime(jrRow.RECON__Forecast_Date__c); jsdatestring = jsdate.toISOString().replace('.000Z','-0000'); */ forecastUrl = url + apiKey + '/' + latitude + ',' + longitude + ',' + forecastdate; console.log('URL: ' + forecastUrl); var sessionId = skuid.utils.userInfo.sessionId; sforce.connection.remoteFunction({ url : forecastUrl, requestHeaders: { "Authorization": "Bearer "+ sessionId, "Content-Type": "application/json" }, method: "GET", onSuccess : function(response) { var objJSON = JSON.parse(response); /* waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu var temperatureMinTimeISO = new Date(objJSON.daily.data[0].temperatureMinTime * 1000 - 32400000); var temperatureMinTimeCalc = skuid.time.getSFDateTime(temperatureMinTimeISO); */ var jsforecastDate = new Date(objJSON.daily.data[0].time * 1000 - 32400000); var sfforecastDate = skuid.time.getSFDate(jsforecastDate); var fields = { RECON__API_Response__c: response, RECON__Daily_Summary__c: objJSON.daily.data[0].summary /* {field: 'RECON__Forecast_Date__c', value: sfforecastDate}, {field: 'RECON__Icon__c', value: objJSON.daily.data[0].icon}, {field: 'RECON__Moon_Phase__c', value: objJSON.daily.data[0].moonPhase}, {field: 'RECON__Precipitation_Intensity__c', value: objJSON.daily.data[0].precipIntensity}, {field: 'RECON__Precip_Intensity_Max__c', value: objJSON.daily.data[0].precipIntensityMax}, {field: 'RECON__Precipitation_Chance__c', value: objJSON.daily.data[0].precipProbability}, {field: 'RECON__Precipitation_Type__c', value: objJSON.daily.data[0].precipType}, {field: 'RECON__Precip_Accumulation__c', value: objJSON.daily.data[0].precipAccumulation}, {field: 'RECON__Daily_Temperature_Min__c', value: objJSON.daily.data[0].temperatureMin}, {field: 'RECON__Dewpoint__c', value: objJSON.daily.data[0].dewPoint}, {field: 'RECON__Wind_Speed__c', value: objJSON.daily.data[0].windSpeed}, {field: 'RECON__Wind_Bearing__c', value: objJSON.daily.data[0].windBearing}, {field: 'RECON__Cloud_Cover__c', value: objJSON.daily.data[0].cloudCover}, {field: 'RECON__Humidity__c', value: objJSON.daily.data[0].humidity}, {field: 'RECON__Pressure__c', value: objJSON.daily.data[0].pressure}, {field: 'RECON__Visibility__c', value: objJSON.daily.data[0].visibility}, {field: 'RECON__Ozone__c', value: objJSON.daily.data[0].ozone}, {field: 'RECON__Daily_Temperature_Max__c', value: objJSON.daily.data[0].temperatureMax} */ }; wlModel.updateRow(wlModel.getFirstRow(),fields); }, onFailure : function(response) { var pageTitle = $('#locationsPageTitle'); var editor = pageTitle.data('object').editor; editor.handleMessages( [ { message: response, severity: 'ERROR' } ] ); } }); } } //Loop through dates of the report while (jrStartDate &lt;= jrEndDate){ // console.log(jrStartDate); if (wldatearray.indexOf(jrStartDateStr) == -1){ getWeatherReport(jrStartDate); } var newDate = jrStartDate.setDate(jrStartDate.getDate() + 1); jrStartDate = new Date(newDate); jrStartDateStr = jrStartDate.toISOString(); }<br>

 



A little cleaned up in the order of things. Vars, then functions, then inline code.

var params = arguments[0],    $ = skuid.$;

var jrModel = skuid.$M(‘JobReport’),
    jrRow = jrModel.getFirstRow(),
    
    // date objects for report start & end dates
    jrStartDate = skuid.time.parseSFDate(jrRow.RECON__Report_Start_Date__c),
    jrEndDate = skuid.time.parseSFDate(jrRow.RECON__Report_End_Date__c),
    
    // date strings for report start & end dates
    jrStartDateStr = jrStartDate.toISOString(),
    jrEndDateStr = jrEndDate.toISOString(),
    
    // ref ids for weather logs
    jrAddress = jrRow.RECON__Job__r.RECON__AddressRef__c;
    flModel = skuid.$M(‘FirstJobLocation’),
    flRow = flModel.getFirstRow(),
    flId = flRow.Id,

    // Get WeatherLogs and set it’s conditions to match job selections. job, start date and end date
    wlModel = skuid.$M(‘WeatherLogs’),
    wlModelJobCond = wlModel.getConditionByName(‘Job’),
    wlModelStartCond = wlModel.getConditionByName(‘StartDate’),
    wlModelEndCond = wlModel.getConditionByName(‘EndDate’);
    
function createWeatherReportRecord(wrdate){
    
    var conditions=[
        {field: ‘RECON__Forecast_Date__c’, value: skuid.time.getSFDate(wrdate)}
        ];

    /* waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu
    sunriseTime = {RECON__Sunrise_Time__c: objJSON.daily.data[0].sunriseTime },
    sunsetTime = {RECON__Sunset_Time__c: objJSON.daily.data[0].sunsetTime },
    time = {RECON__Weather_Report_Time__c: objJSON.daily.data[0].time },
    precipIntensityMaxTime  = {RECON__Precip_Intensity_Max_Time__c: objJSON.daily.data[0].precipIntensityMaxTime },
    temperatureMinTime = { RECON__Temperature_Min_Time_Time__c: temperatureMinTimeCalc },
    temperatureMaxTime  = {RECON__Temperature_Max_Time__c: objJSON.daily.data[0].temperatureMaxTime },
    /
    
    wlModel.createRow();//({ additionalConditions: conditions});
}

function getWeatherReportRecord(urlDate){

    /
waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu
    jsdate = skuid.time.parseSFDateTime(jrRow.RECON__Forecast_Date__c);
    jsdatestring = jsdate.toISOString().replace(‘.000Z’,‘-0000’);
    /

    // base url & url parameters from job. item url parameter to come from start/end date loop
    // forecast.io URL format:
    // https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME
    var url = ‘https://api.forecast.io/forecast/’,
        apiKey = ‘27b81979ec35eddcc6b95323b9546d78’,
        latitude = jrRow.RECON__Job__r.RECON__AddressRef__r.RECON__Geocode__Latitude__s,
        longitude = jrRow.RECON__Job__r.RECON__AddressRef__r.RECON__Geocode__Longitude__s;
    
    forecastUrl = url + apiKey + ‘/’ + latitude + ‘,’ + longitude  + ‘,’ +  urlDate;
    console.log('URL: ’ + forecastUrl);
    var sessionId = skuid.utils.userInfo.sessionId;
    sforce.connection.remoteFunction({
        url : forecastUrl, 
        requestHeaders: {
            “Authorization”: "Bearer "+ sessionId, 
            “Content-Type”: “application/json”
        }, 
        method: “GET”, 
        onSuccess : function(response) { 
    
            var objJSON = JSON.parse(response);
            
            /
waiting for estimate ## to get proper date/time based on geocode of address. PV 2015-01-07 http://goo.gl/xQRJu
            var temperatureMinTimeISO = new Date(objJSON.daily.data[0].temperatureMinTime * 1000 - 32400000);
            var temperatureMinTimeCalc = skuid.time.getSFDateTime(temperatureMinTimeISO);
            /
            
            var jsforecastDate = new Date(objJSON.daily.data[0].time * 1000 - 32400000);
            
            var fields = {
                RECON__API_Response__c: response,
                RECON__Daily_Summary__c: objJSON.daily.data[0].summary
                /

                {field: ‘RECON__Icon__c’, value: objJSON.daily.data[0].icon},
                {field: ‘RECON__Moon_Phase__c’, value: objJSON.daily.data[0].moonPhase},
                {field: ‘RECON__Precipitation_Intensity__c’, value: objJSON.daily.data[0].precipIntensity},
                {field: ‘RECON__Precip_Intensity_Max__c’, value: objJSON.daily.data[0].precipIntensityMax},
                {field: ‘RECON__Precipitation_Chance__c’, value: objJSON.daily.data[0].precipProbability},
                {field: ‘RECON__Precipitation_Type__c’, value: objJSON.daily.data[0].precipType},
                {field: ‘RECON__Precip_Accumulation__c’, value: objJSON.daily.data[0].precipAccumulation},
                {field: ‘RECON__Daily_Temperature_Min__c’, value: objJSON.daily.data[0].temperatureMin},
                {field: ‘RECON__Dewpoint__c’, value: objJSON.daily.data[0].dewPoint},
                {field: ‘RECON__Wind_Speed__c’, value: objJSON.daily.data[0].windSpeed},
                {field: ‘RECON__Wind_Bearing__c’, value: objJSON.daily.data[0].windBearing},
                {field: ‘RECON__Cloud_Cover__c’, value: objJSON.daily.data[0].cloudCover},
                {field: ‘RECON__Humidity__c’, value: objJSON.daily.data[0].humidity},
                {field: ‘RECON__Pressure__c’, value: objJSON.daily.data[0].pressure},
                {field: ‘RECON__Visibility__c’, value: objJSON.daily.data[0].visibility},
                {field: ‘RECON__Ozone__c’, value: objJSON.daily.data[0].ozone},
                {field: ‘RECON__Daily_Temperature_Max__c’, value: objJSON.daily.data[0].temperatureMax}
                */
            };
            
            wlModel.updateRow(wlModel.getFirstRow(),fields);
        }, 
        
        onFailure : function(response) { 
            var pageTitle = $(‘#locationsPageTitle’);
            var editor = pageTitle.data(‘object’).editor;
            editor.handleMessages(
                    [
                        {
                            message: response,
                            severity: ‘ERROR’
                        }
                    ]
                );
            }
    });
}


    
function waitforsave(){
    console.log(‘modelsaved’);
}

// set conditions
wlModel.setCondition(wlModelJobCond,jrRow.Id);
wlModel.setCondition(wlModelStartCond,jrStartDate);
wlModel.setCondition(wlModelEndCond,jrEndDate);

// activate conditions
wlModel.activateCondition(wlModelJobCond);
wlModel.activateCondition(wlModelStartCond);
wlModel.activateCondition(wlModelEndCond);

// query model
wlModel.updateData();

// deactivate conditions
wlModel.deactivateCondition(wlModelJobCond);
wlModel.deactivateCondition(wlModelStartCond);
wlModel.deactivateCondition(wlModelEndCond);

var wldatearray = ;

// Gather Dates from wlModel in array so they can be searched for in the following while loop
for (var datakey in wlModel.data) {
    var dataobj = wlModel.data[datakey];
    for (var prop in dataobj){
        if(dataobj.hasOwnProperty(prop) && prop == ‘RECON__Forecast_Date__c’ ){      
            wldatearray[wldatearray.length] = skuid.time.parseSFDate(dataobj[prop]).toISOString();
            // console.log(wldatearray);
        }
    }
}

var forecastdate;

//Loop through dates of the report
while (jrStartDate <= jrEndDate){
   // console.log(jrStartDate);
   
   if (wldatearray.indexOf(jrStartDateStr) == -1){

        createWeatherReportRecord(jrStartDate);

        wlModel.save(waitforsave());

        forecastdate = jrStartDate.toISOString().substring(11,0).concat(‘12:00:00’);
        
        getWeatherReportRecord(forecastdate);
        
   }
   
   var newDate = jrStartDate.setDate(jrStartDate.getDate() + 1);
   jrStartDate = new Date(newDate);
   jrStartDateStr = jrStartDate.toISOString();
}




Asynchronous and callbacks. I learned those the hard way today. Boiled my snippet down to absolute barebones and kept getting odd behaviour. Thought I was using the callback option properly. Didn’t realize that I needed to type out “callback: function(result)…” Barebones snippet works now. Going to bed.

Glad you figured it out Pat, bummer it was the hard way…

Moshe’s correct, calls to model.save() or model.updateData() are asynchronous, which means that you can’t have code like the following:

1 model.updateData();
2 model.deactivateCondition(condition)…

Because Line 2 will not wait for Line 1 to finish before it runs, so you’ll get unexpected behavior.

Unfortunately Skuid’s API’s with callbacks are slightly different for updateData() and save(), but I recommend using the Promise based approach instead, which is consistent for both:

// UPDATE DATA
$.when(model.updateData())
   .done(function(result){
       var condition = model.getConditionByName(‘MyCondition’);
        model.deactivateCondition(condition);
   })
   .fail(function(result){
        console.log(‘there was a problem’);
   });

// SAVE
$.when(model.save())
   .done(function(result){
       if (result.totalsuccess) {
           console.log(‘heck yeah’);
       } else {
          console.log(‘something went wrong…’);
          console.log(result);
       }
   })
   .fail(function(result){
        console.log(‘there was a really bad problem, like connecting to the server’);
   });




Perfect! Explains a few things trying to use the callbacks of each.

I’d say I’m starting to encroach on intermediate level javascript. At least hopefully I’d like to think so. :smiley:

Pat I would say that you’re higher than intermediate already! But anyway I kind of forgot about the difference between :

model.save(callback:myCallbackFunction());


and

model.updateData(myCallbackFunction);


I would recommend this post as a simple explanation of what exactly a callback is/does:

http://www.impressivewebs.com/callback-functions-javascript/

Did you get your snippet working?

Thanks for the vote of confidence. Really pushing hard to get this down to the same thing as typing an email. A few months to go before that happens I’d say.

Certainly going to read that article.

I got the barebones version of it working now. Should be pretty quick to get it going.

Can I use the “$.when” on “sforce.connection.remoteFunction”?

No, that’s a Salesforce API method and they don’t implement the $.when() approach.

Do you know of a way to do a callback on this salesforce API from javascript?

The forecast.io api does have callback option, but I’m not too sure how to implement it. Any ideas?
https://developer.forecast.io/docs/v2

I’d otherwise use this suggestion if I didn’t have to use sforce.connection.remoteFunction.

http://stackoverflow.com/questions/18132790/forecast-io-api-usage-with-jquery

This should work, just dump all of your code inside the save:

model.save({callback:function(){ <br>sforce.connection.remoteFunction({<br>&nbsp; &nbsp; &nbsp; &nbsp; url : forecastUrl,&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; requestHeaders: {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Authorization": "Bearer "+ sessionId,&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Content-Type": "application/json"<br>&nbsp; &nbsp; &nbsp; &nbsp; },&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; method: "GET",&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; onSuccess : function(response) {&nbsp;<br>&nbsp; &nbsp;&nbsp;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var objJSON = JSON.parse(response);<br>//etc....<br>}<br>});<br>}});

Wait. The callback function is run before or after the save method?

After

Great, perfect & awesome!

TADA!!!
The code changed so so much. Didn’t really get asynchronous and callbacks til now.