You can absolutely invoke code on action buttons. Almost all of the action buttons in wizards, page titles, table actions etc allow a “Custom” type which then exposes a snippet name property. Write your Javascript file in our resources section (or include a reference there to some external file) and you can go to town.
Here is a previous forum post where an example of this is discussed: http://community.skuid.com/t/wait_for_an_update_to_complete_and_then_retrieve_the_firs…
Hi Charlie, Yes, this is possible. Wizard Step Actions can be of type “Custom”, which lets you execute a Skuid Snippet. So you enter the name of the Snippet, and then you define the Snippet from the JavaScript Resources tab, by creating a new JavaScript Resource of type “Inline(Snippet)”. All Skuid Snippets are passed context params/arguments relevant to the Snippet scenario — so for a Wizard Step navigation action, you are handed a reference to the Step object you are on, as well as to the parent Wizard object itself. So first off, you add a new Action button to a Wizard Step, then you set its type to Custom, and enter the name of a Skuid Snippet, e.g. “GoToStep2”: Then in your JavaScript Resources, create “GoToStep2” as a new JavaScript Resource of type “Inline (Snippet)”: For my example, we’ve got a New Opportunity Wizard. On the first step you enter details about the Opportunity. Then the “Go to Step 2” button runs our GoToStep2 Skuid Snippet, which I’ll post here and then explain:
var params = argumentsl0], step = params.step; // Make sure that a Pricebook was selected on our Opportunity Model var OpportunityModel = skuid.model.getModel('Opportunity'), Opp = OpportunityModel.getFirstRow(); if (!OpportunityModel.getFieldValue(Opp,'Pricebook2Id')) { alert('You must select a Pricebook before proceeding.'); } else { // Create a default row in our LineItems model, // (if there is not already one) // now that we have a Pricebook selected var LineItemsModel = skuid.model.getModel('OpportunityLineItems'); if (LineItemsModel.data.length === 0) { var newLineItem = LineItemsModel.createRow({ additionalConditions: t { field: 'Quantity', value: 1 } ] }); } step.navigate('step2'); }
This Snippet does some checking on the values in the new Opportunity record: specifically here, it makes sure that a Pricebook has been selected for the Opportunity. Of course this is just an example, you could have pre-selected the Opportunity’s Pricebook, but it serves the example. If the user has not selected a Pricebook, the user gets an error, and no step navigation is performed. If the user HAS picked a pricebook, though, we do 2 things. First, we check to see if there is a record in our LineItems model yet. If not, we create one, passing in some default field values. Then, we navigate to Step 2 by calling the “navigate()” method of the Step object that was handed to us in our Snippet’s arguments. If you’re wondering about what arguments are handed to Snippets in different contexts, then best way to find out is to do a console.log on the arguments, e.g. console.log(arguments); I usually immediately declare a “params” variable in Skuid Snippets, set to the first argument passed in to the Snippet, which is usually an object. Here’s what the Wizard basically looks like:
BEAUTIFUL. Didn’t know that it would be passed to the snippet. On a side note… once again… wish the documentation for these things was a bit more concrete, but I understand. Plus, I can’t complain when you provide great answers like this within minutes.
I wanted to answer the “running logic” part of your question first before addressing the “validating user input” in more detail. While you can manually validate user input in your Snippet logic, as we did above checking that the Pricebook2Id field had been populated, you might want to check to make sure all Required Fields are populated. Skuid always checks required fields when you run model.save(), but it does not do this when you navigate between steps unless you do the Save navigation action. So you have a couple of options here from your Snippet: Option 1: Save your Opportunity Model and only go to Step 2 if there are no errors. Skuid will perform client-side validation of required fields before the Save operation is ever sent to the server. One benefit of this is that, rather than waiting until the end to save everything, you handle the multi-record creation piece by piece. But this can also be a con, because then you’d have to delete all your records if the user wanted to cancel at some later stage in the wizard. (SNIPPET CODE)
var params = arguments 0], step = params.step; var OppModel = skuid.model.getModel('Opportunity'); /* * Save is Asynchronous, * so we won't decide whether to navigate * to Step 2 until we get our async result back. * In the meantime, we block the UI. * (Skuid includes jQuery BlockUI) */ skuid.$.blockUI({ message: 'Saving Opportunity...' }); // This performs client-side Required Field validation // before it ever hits the server OppModel.save({callback: function(result){ // Regardless of what happens, unblock the UI skuid.$.unblockUI(); if (result.totalsuccess){ step.navigate('step2'); } else { // Error messages will be displayed in red on the screen, // but we can also check the result object // to see the specifics of which records failed and how console.log(result.insertResults); } }});
Option 2: Don’t actually save the Opportunity Model, just run client-side Required Fields validation. The trick here is that required field validation is actually performed by Skuid Lists, an internal component. Field Editor, Table, and Queue are the main components that have associated Lists under the hood. Lists are registered with Models, so each Model has an array property called registeredLists that contains all Lists registered on the Model. So, we can iterate over all Lists registered on a particular Model, or just get a particular one, and call validateRequiredFields() on the List, like this, which returns a list of error objects); (SNIPPET CODE)
var params = arguments 0], step = params.step; var OppModel = skuid.model.getModel('Opportunity'); var validationErrors = i]; skuid.$.each(OppModel.registeredLists,function(i,list){ // Will display error messages to the user var errors = list.validateRequiredFields(); if (errors.length) { skuid.$.each(errors,function(){ validationErrors.push(this); }); } }); if (validationErrors.length) { alert(validationErrorsd0].message); } else { step.navigate('step2'); }
This is great. And just to join up some dots on the forum, Zach’s Option 2 above answers my question from last month here: http://community.skuid.com/t/run_validation_on_wizard_next