Syntax Help Needed - Can't get changes to a model to save using JavaScript

I have the following snippet that executes without errors but doesn’t actually save the records.   It’s being called from a mass edit rows button. The records are displayed in a table and I can edit the records and they save correctly.  They do not save when this code executes.

This is all happening on the 2nd page of a wizard, if that matters.

I can see the value I want being changed while the code is executing through alerts or through the console, but the record changes are never saved to the database.

Salesforce is the data source.  The list of selecteditems is coming from the DeliverableActivities model.  All I’m trying to do is update the value of a lookup field on the rows that are selected in a table bound to the model.  I retrieved the value on the first step of the wizard and stored it in a UI only data model called Variables.  I read that there were some issues with UI fields, so I took the value from the Variable and set it to a string variable to see if that would work.  It didn’t, but that code is still there.

I believe I’m calling updateRow incorrectly or the save method incorrectly, but I don’t get any errors.

Any help is greatly appreciated.

var params = arguments[0], $ = skuid.$,
    list = arguments[0].list,
    selectedItems = list.getSelectedItems();
    
var models = skuid.model.map();
var Variables = models.Variables;
var da = models.DeliverableActivities;
var vRow = Variables.getFirstRow();
var invoiceID = vRow.Opportunity_Invoice_ID + ‘’;

    $.each( selectedItems,
        function( i, item )
        {
            var row = item.row;
            try {
                da.updateRow(row, { Opportunity_Invoice__c : invoiceID});
            } catch(e) {
                window.alert(e + ‘’);
            }
        }
    );

skuid.model.save([da], {callback: function(result) {
   if (result.totalsuccess) {
       //window.alert(‘models saved’);
       try {
            skuid.model.updateData([da]);
        } catch (e) {
            window.alert(e);
        }
        
   } 
    
}});

Hi Steve,

If your ultimate goal is to “update the value of a lookup field on the rows that are selected in a table bound to the model” it seems like there would be a declarative way to do this. Perhaps there’s more to your scenario that necessitates some code but if there’s a way to avoid code, Skuid’s all for it. A mass action can trigger an action sequence that will take rows in context, and “update a field on row(s)” with a particular value. it sounds like you’re capturing the desired value in step 1 of your wizard, so you should be able to use global merge syntax to point to it in the action sequence. This may sound pretty general - please let us know what hurdles you’ve run into with an action sequence for this, and we can try to help work through them. 

If you do need to use a snippet for this, have you gone through and checked if each of your declared variables is defined? I’ll often do this just by wrapping the variables one by one in a console.log. If one of your variables is ending up undefined, the $.each function may not have any items to work on, so there might not even be a chance for the catch to fire off. 

Assuming that these field names you’re using are correct in your code: Opportunity_Invoice_ID and Opportunity_Invoice__c, this looks like it should work.

First question: what object are you trying to update? It’s clearly a custom field, but what object?

What I would do next is to verify that what you think is happening is actually happening.

1. After you update all of your rows, do a console.log to see what the Opportunity_Invoice__c field actually is now, e.g. do this right after your $.each( ) loop:

selectedItems.forEach(function(item) {
   console.log(da.getFieldValue(item.row, “Opportunity_Invoice__c”, true));
});

2. Inspect the save result to verify that there weren’t any errors:

if (result.totalsuccess) {
   … do this if everything worked
} else {
   console.log(“everything did not go as planned”);
   console.log(result);
   // use Chrome’s/Firefox’s JavaScript console to inspect the updateResults / insertResults
}

Stepping back, though, I’d agree with Mark — this should be very straightforward to do without code using an Action sequence, and we’d recommend that for sure. Here’s what the actions would be that your Table Mass Action should perform:

1. Update a field on rows
 - Model: DeliverableActivities
 - Field: Opportunity_Invoice__c 
 - Value: {{$Model.Variables.data.0.Opportunity_Invoice_ID}}
 - Rows to Use: Rows in Context

2. Save Model changes
 - Models: DeliverableActivities

3. Query Model
 - Model: DeliverableActivities

You could also add a “Show message” Action at the start (and an “Unblock the UI” action at the end!), as well as an on-error “Show message” action to the Save Model action.

Thanks for the replies.  There is a lot more code here than what I posted.  I narrowed it down to just the code that was having problems.  The reason I think I need code is that I need to aggregate fields on the selected rows to update a header row (basically, invoice and invoice line items).  Is there any way to keep track of aggregates based on selected records in memory without code?

All of the code works and all of the fields in every other model and record get updated correctly.  The only field that doesn’t get updated is the Opportunity_Invoice__c field, which is a lookup to a custom object.  After reading some other threads, I added a UI only field called InvoiceID to the Deliverable Activity model then added a Row Action on the model to update the Opportunity_Invoice__c field when the InvoiceID is updated.  That actually worked.  So, I know that the value I am passing of the ID is correct.

Based on your responses, my syntax is correct to update the field, and I know the value of the ID is correct, so why isn’t this updating?  I thought maybe because it is a reference field that I need to pass in a reference to a model of the the record instead of just the ID, but it doesn’t sound like that is true.   Is there any reason that setting an ID field wouldn’t work?  Variables is actually a UI only model that I’m storing values in.  I have the field Opportunity_Invoice_ID on Variables declared as a text field length 18.  Is there another field type I should be using?

Did you do the piece i recommended with the console.logs() to check whether result.totalsuccess was true or false, and to see if there were any errors with the save? This is the first place I’d start.

I actually don’t want to save any records at this point.  I only added the save to see if that made any difference in the behavior and it didn’t.  But the problem appears to occur on the update, not the save.  Once I added the UI only field, the records update as desired without having to do a save.  I have performed a try catch on the updateRow method and no error is thrown.  From reading the documentation, the updateRow method doesn’t return anything for me to interrogate.

Although I agree that declarative is preferrable, using the declarative to set the Id with the global variables does not work in this scenario.  In the first step, I am picking one invoice from a list of invoices and the global merge syntax always provides the first row in the model, not the row I select.  I have read that the behavior I am seeing is consistent with what others experience.  

I tried to do everything I’m doing declaratively and couldn’t make it work.  It actually now behaves exactly as I want it to, but I have to use code and what I consider a work around with the model action.

Here is what I’m trying to accomplish and if I can do it declaratively, please let me know how.

We have a list of invoice records in Salesforce in an object Opportunity Invoices.  Our consultants log their billable time in an object called Deliverable Activities.  Each billing period our finance department associates Deliverable Activities with an Opportunity Invoice so we can bill our customers.  What they want to occur is:

  1. Display a list of Opportunity Invoices and allow them to create a new invoice if none exists.
  2. Select an invoice from the list and display a list of Deliverable Activities that can be billed.  I need to ensure they only pick one Opportunity Invoice from the list, so I wrote code to stop the progress if they select more than one.
  3. Allow them to pick the Deliverable Activities, associate them with the selected Opportunity Invoice, aggregate the total hours and total billable amount of all selected Deliverable Activities and update the totals on the Opportunity Invoice.
  4. Create the invoice record in Salesforce and simultaneously create the invoice in Quickbooks Online
  5. While creating the invoice in Quickbooks Online, attach the original statement of work plus an excel spreadsheet and a pdf of all the Deliverable Activities included in the invoice then automatically email the invoice to the customer.
  6. When the invoice is created in Quickbooks, update the related Opportunity Invoice in Salesforce and automatically create a new Opportunity Invoice to be used for the next billing period.
I have steps 1-3 working correctly using a combination of snippets and declarative.  I’m using one page with a popup.   I’m working on steps 4,5 & 6 now.  

Thanks for all the help!