Using Skuid with JavaScript: A Primer

The Skuid JavaScript API is powerful, but it can be challenging to understand at first if you don’t have much experience with JavaScript. To illustrate some basic JavaScript and Skuid API concepts, we’ll be using some common APIs on a runtime Skuid page—showing how these APIs can interact with the elements of that page.

Prerequisites

JavaScript basics

JavaScript is the primary programming language powering Skuid, and it’s what you’ll be working in to extend Skuid applications you build in the Composer.

This widely used web technology has lots of concepts and quirks which you may encounter while building with Skuid. That’s why Skuid does a lot of the heavy lifting for most applications.

You don’t need to know the nuances of JavaScript to use it in Skuid, but learning more will help you build and understand more complex implementations. If you’re already familiar with variables, data types, and conditionals, you know more than enough to use JavaScript in Skuid.

To learn about these basic concepts, expand the section below. To continue learning, consider browsing MDN’s JavaScript learning material.

Basic concepts [[]]

  • Variables: Variables are containers of information. They are assigned a name, which can be referenced and used in JavaScript logic. Basic variable creation looks like this:

    1
    let myVariable = "A value."
    

    You can declare variables with these keywords: let, const, and var. For this primer, we’ll just be using the let keyword.

  • Data types: Data can be stored as different “types” in JavaScript, which have different rules on how the data looks and what can be done to it. The most common ones you’ll encounter with Skuid include:

    • Booleans: A true/false value:

      1
       true
      
    • Numbers: A number, listed without a quotation mark:

      1
      5
      
    • Strings: A piece of text encased in quotations marks (or backticks in newer JavaScript):

      1
      "This is a string!"
      
    • Arrays: A series of values stored in an ordered list, encased in brackets:

      1
      ["This is an array of strings", "This is the next value", "And this is the last one"]
      
    • Objects: A more complex data type that holds key-value pairs. Each value can be its own data type, even another object.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      {
        "boolean": true,
        "number": 5,
        "string": "This is a string!"
        "array": ["This is an array of strings", "This is the next value", "And this is the last one"],
        "object": {
          "isThisObjectNested": true
          }
      }
      
  • Conditionals: “Conditionals” are pieces of logic code that dictate when other pieces of code can run (much like Skuid’s own display logic rules). These typically appear as if/else statements that utilize comparison operators (like ==), though there are other concepts like switch statements and ternary operators as well.

Following along on a Skuid page

To test the APIs mentioned in this primer, we recommend working on a multi-record page in a personal developer org or a sandbox org. For this example, we assume you’re working with the page described in the Build a Custom List Page tutorial.

You can follow along in a separate window using your own Skuid page or using this sample page with example data.

Using this page, we’ll show how to do the following programmatically:

  • Access Skuid model data
  • Update rows of data within a model
  • Block the UI to display popup messages to the end user

Whether you’re writing a small snippet or a completely custom component, the API examples provided in this primer illustrate foundational concepts for future development.

Specify the Skuid runtime

In Skuid’s v2 page API, each page’s runtime is “sandboxed,” meaning each Skuid page within the browser window has its own set of APIs that don’t (by default) talk to other Skuid pages. These different pages are considered different “runtimes” or page contexts.

To access a page’s APIs, you must first specify the runtime you’re interacting with. In our example we’re only accessing a single Skuid page. But this is an important step when working with multiple pages in one browser window—like when using the Page Include component.

To do this we’ll be using Skuid’s skuid.debug API, which is specifically design for use in browser consoles at runtime.

  1. In the previewed page’s browser window, open the developer console.
  2. Type skuid.debug.page() in the console. The page’s runtime object should be returned in your console, alongside some usage notes for the debug API.

With the page’s runtime context returned, we now have access to the individual APIs of the page.

But skuid.debug.page() is a lot of text to type for each command. Let’s create a variable to reference this command as a shortcut. This common programming practice makes code easier to type and read.

1
let skuidPage = skuid.debug.page()

Now, when working in this browser window, typing skuidPage is effectively the same as typing skuid.debug.page().

1
2
3
4
5
skuid.debug.page().version;
// Returns the Skuid version of the page

skuidPage.version;
// Returns the Skuid version of the page, now with less typing!

We’ll use skuidPage for all the examples below.

On writing snippets

When you start writing your own JavaScript snippets in the Composer, you won’t have to specify your Skuid runtime. Why is that? Because when a snippet is stored in a Skuid page, that snippet knows its context is the page it’s stored in.

So when writing snippets in the Composer, don’t write this:

1
2
3
4
skuid.debug.page().version;
// or
let skuidPage = skuid.debug.page();
skuidPage.version;

Just use skuid:

1
skuid.version;

Keep this in mind when reading our API reference material; you’ll see skuid instead of skuidPage because our reference assumes you are working within a snippet in the Composer, and your runtime context is already set.

Accessing model data

Seeing all models on a page

First, let’s see which models are on the page.

  1. Open your browser’s console.
  2. Type skuidPage.model.map() and press enter. Information about the page’s models, including the Account model, appears in the console.

This happens because we’re using the skuid.model.map() API to return an object that has all of model IDs as its keys, with the model data as values of those keys.

What if—for your use case—you’d like to receive that data as an array because of the different methods available for array types. To retrieve this as an array, use the getModelList() API:

1
skuidPage.model.getModelList();

All of your models are returned, but this time as an array.

You can access some Skuid information, like page models, in a variety of data types. Use the API that returns the data type most appropriate for your use.

For example, enter the following:

1
2
modelsObject = skuidPage.model.map();
modelsArray = skuidPage.model.getModelList();

Now you can reach your Account model in two ways:

1
2
modelsObject.Account;
modelsArray[0];

But this isn’t the most efficient or most reliable way to reach a specific model’s data.

Accessing a single model’s data

One common use case for JavaScript in Skuid is accessing or updating the data of one or more models. To do that, you’ll need to access that model as a JavaScript object.

Type the following:

1
skuidPage.model.getModel('Account');

This function returns model data as a skuid.model.Model object, much like the above code, but we’re reaching it in one step. Now let’s use a variable to reference this model, so everything we do moving forward is more readable.

1
let account = skuidPage.model.getModel('Account');

Note

When creating variable shortcuts, undefined will often be returned by the console. This is normal, and entering your variable after defining it will return the object you created a shortcut to.

After declaring our shortcut variables, typing either skuidPage.model.getModel('Account').id or account.id returns the same data. To demonstrate how your new variable works, try entering some of the following in your browser’s console:

1
2
3
4
5
6
7
8
9
account.data;
// Returns all model rows as an array of objects.

account.dataMap;
// Returns all model rows as an object, with each row as a property.

account.conditions;
// Returns all model conditions as an array of objects.
// This is likely an empty array in this sample page.

Interacting with your model

Now that we know how to reach our model’s data, let’s look at how we can interact with that data programmatically.

First, create a new row on your table by typing account.createRow() in your console

1
2
account.createRow();
// A new, empty row appears at the top of the Table component.

Simple enough, but how do we input data into our newly created row?

Updating a row

1
2
3
4
account.updateRow(account.getFirstRow(), { Name: 'My First API Row Update!' });
// updateRow accepts two parameters:
// the row to update
// the updates to make (as a JavaScript object)

Let’s break down how the updateRow() method used here tells Skuid to update a row.

  • The first parameter is the row we want to update. We use the getFirstRow() method as the first parameter, which tells Skuid to look for the model’s first row at the top of that model’s data and return it as an object that the updateRow() function can recognize.

  • The second parameter is a JavaScript object with properties that correlate to:

    • The ID of our name field: “Name"
    • The value to update that field to: “My First API Update!'

You could also:

  • Use an explicit object literal for your row ID parameter, e.g. {Id:"0012603000X4aYYAAZ"}.

  • Update more than one field in a row at a time:

    let updates = {
      Name: "A good name",
      BillingCity: "A cool city",
      CustomField__c: "A custom value for a custom field"
    };
    
    account.updateRow(account.getFirstRow(), updates);
    
    // Notice that we created our updates in a separate object,
    // then used that object as the parameter.
    // This leads to more readable, easier to update code.
    
  • Create and update your row in one line:

    1
    account.updateRow(account.createRow(),{Name:'Created in one line'});
    

Since our table is currently in inline edit mode, let’s cancel all of our changes to the model so far by using the cancel() method.

1
account.cancel();

Canceling specific rows and saving

Now, let’s create two rows that are stored within variables so we can have more granular control over what we do and do not cancel. Copy and paste the following in your console:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
let workingRow = account.createRow();
// The newly created row returned by this function will be known as "workingRow"

account.updateRow(workingRow, { Name: 'Working Row' });
// Using our newly created and identified row object as our updateRow parameter

let anotherRow = account.createRow();
// A second created row stored in another unique variable

account.updateRow(anotherRow, { Name: 'Another Row' });
// Updating that second row

Now we have consistent identifiers for the rows our JavaScript has created. This can be essential when writing snippets or custom component that manipulate model data. By using these row identifiers, we can update them—even using data from one row in the other. We can also abandon these rows, individually cancel them, easily.

First, let’s look at how we can retrieve data from a particular row:

1
anotherRow.Name;

Entering this will return the value of the Name field on our anotherRow row in our account model.

Now that we know we can access that data programmatically, let’s use it to update our workingRow’s Name field. Then we can cancel our extra row by using abandonRow().

1
2
3
4
5
account.updateRow(workingRow,{Name:anotherRow.Name});
// Updating the workingRow using data from a different row that is stored in a variable, as opposed to using an explicit string

account.abandonRow(anotherRow);
// Abandoning a specific row allows us to cancel one row without destroying them all

And with that, we’ve made all the changes we want to in our data object.

Let’s save those changes with another API:

1
account.save();

But wait! Changed your mind? Don’t want that garbage row you just saved in your data? Easy fix: delete it instead.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
workingRow;
// Even though it's saved, the row is still stored within its variable.
// The row's ID field was updated when it was saved,
// but that field is also updated within your object as well.

account.deleteRow(workingRow);
// Marks the row for deletion,
// but it won't be deleted from your data object until you use save()

account.save();
// Model changes are saved, and the row is deleted.

Interacting with the user interface

And with that, you’ve accomplished a few common Skuid activities entirely through JavaScript. Let’s display a celebratory message with the blockUI() function to illustrate how you can also use JavaScript for user interface (UI) elements as well.

To do this, we’ll create an object that contains our configuration options and then use that object in our API. In contrast to the APIs we used earlier, we’ll be defining our options and our logic on separate lines. This keeps the code more readable (and easier to update):

1
2
3
4
let config = {
    message: `You've used Skuid exclusively through JavaScript! You're on your way to becoming a pro Skuid developer.`
};
skuidPage.$.blockUI(config);

When you’re finished admiring your work, you can unblock your UI just as easily:

1
skuidPage.$.unblockUI();

This is a very basic example. Most UI-related JavaScript you’ll write involves custom field renderers, which determine the appearance of fields within Skuid components. Doing this requires knowledge of more advanced concepts like the virtual DOM and Hyperscript syntax. But with the basics you’ve learned here, you have the foundations to learn those as well. Happy coding!