Use the Write to Data Store Entity Smart Service Function on an Interface

This function recipe provides the data for many interface recipes. Working through this recipe first will help ensure that you have data to show in the live view of other recipes.

Interface recipes give you an opportunity to explore different interface design patterns. To learn how to directly use interface recipes within your interfaces, see Adapt an interface recipe to Work with My Applications.

Goal

Allow the user to publish several rows of data to a table through the a!writeToDataStoreEntity() smart service function.

This scenario demonstrates:

  • How to use the a!writeToDataStoreEntity() smart service function to persist data directly from an interface
  • How to use the 'showWhen' parameter of an interface component to choose one component or another, based off a user's interactions.

Setup

Try to follow these setup steps verbatim. However, if you do need to adjust any of these values, you'll need to ensure that you making the necessary modifications to interface recipes that depend on this data.

This example uses a custom data type. In an appropriate application, create anemployee custom data type (leave namespace set to default) with the following fields:

  • id (Number (Integer))
    • Select the Key icon and set this field to Primary Key
    • click the Auto-generate checkbox to let the database handle value assignment
  • firstName (Text)
  • lastName (Text)
  • department (Text)
  • title (Text)
  • phoneNumber (Text)
  • startDate (Date)

Next, let's create a data store within the same application where the CDT was created:

  1. Create a new data store. Name the data store with a unique relevant name, like Employee DS.
  2. Configure the data source to a data source you can access
  3. In the data store, create a data store entity called employee
    • Set the data type to employee
  4. Save & Publish the data store
    • Optionally, check the data base table to see that an employee table has been created

Finally, let's create constant within that same application so we can use the newly created data store in an expression:

  • Create a new constant. Name the constant EMPLOYEE_DSE.
  • Set the Data Type to Data Store Entity
  • Set the Data Store dropdown value to the Data Store created above
  • Set the Data Store Entity to Employee

Now that we've created the dependent objects and custom data type, let's move on to the main expression.

Expression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
=load(
  local!dataToLoad: cast(
    'type!{urn:com:appian:types}Employee?list',
    {
      { firstName: "John" , lastName: "Smith" , department: "Engineering" , title: "Director" , phoneNumber: "555-123-4567" , startDate: today()-360 },
      { firstName: "Michael" , lastName: "Johnson" , department: "Finance" , title: "Analyst" , phoneNumber: "555-987-6543" , startDate: today()-360 },
      { firstName: "Mary", lastName: "Reed" , department: "Engineering" , title: "Software Engineer" , phoneNumber: "555-456-0123" , startDate: today()-240 },
      { firstName: "Angela" , lastName: "Cooper" , department: "Sales" , title: "Manager" , phoneNumber: "555-123-4567" , startDate: today()-240 },
      { firstName: "Elizabeth" , lastName: "Ward" , department: "Sales" , title: "Sales Associate" , phoneNumber: "555-987-6543" , startDate: today()-240 },
      { firstName: "Daniel", lastName: "Lewis" , department: "HR" , title: "Manager" , phoneNumber: "555-876-5432" , startDate: today()-180 },
      { firstName: "Paul" , lastName: "Martin" , department: "Finance" , title: "Analyst" , phoneNumber: "555-609-3691" , startDate: today()-150 },
      { firstName: "Jessica" , lastName: "Peterson" , department: "Finance" , title: "Analyst" , phoneNumber: "555-987-6543" , startDate: today()-150 },
      { firstName: "Mark" , lastName: "Hall" , department: "Professional Services" , title: "Director" , phoneNumber: "555-012-3456" , startDate: today()-150 },
      { firstName: "Rebecca" , lastName: "Wood" , department: "Engineering" , title: "Manager" , phoneNumber: "555-210-3456" , startDate: today()-150 },
      { firstName: "Pamela" , lastName: "Sanders" , department: "Engineering" , title: "Software Engineer" , phoneNumber: "555-123-4567" , startDate:today()-120 },
      { firstName: "Christopher" , lastName: "Morris" , department: "Professional Services" , title: "Consultant" , phoneNumber: "555-456-7890" , startDate: today()-120 },
      { firstName: "Kevin" , lastName: "Stewart" , department: "Professional Services" , title: "Manager" , phoneNumber: "555-345-6789" , startDate: today()-120 },
      { firstName: "Stephen" , lastName: "Edwards" , department: "Sales" , title: "Sales Associate" , phoneNumber: "555-765-4321" , startDate: today()-120 },
      { firstName: "Janet", lastName:"Coleman" , department: "Finance" , title: "Director" , phoneNumber: "555-654-3210" , startDate: today()-90 },
      { firstName: "Scott" , lastName: "Bailey" , department: "Engineering" , title: "Software Engineer" , phoneNumber: "555-678-1235" , startDate: today()-30 },
      { firstName: "Andrew" , lastName: "Nelson" , department: "Professional Services" , title: "Consultant" , phoneNumber: "555-789-4560" , startDate: today()-30 },
      { firstName: "Michelle" , lastName: "Foster" , department: "HR" , title: "Director" , phoneNumber: "555-345-6789" , startDate: today()-30 },
      { firstName: "Laura" , lastName:"Bryant" , department: "Sales" , title: "Sales Associate" , phoneNumber: "555-987-6543" , startDate: today() },
      { firstName: "William" , lastName: "Ross" , department: "Engineering" , title: "Software Engineer" , phoneNumber: "555-123-4567" , startDate: today() }
    }
  ),
  local!pagingInfo: a!pagingInfo(
    startIndex: 1,
    batchSize: 20,
    sort: a!sortInfo(field: "id", ascending: true)
  ),
  with(
    local!datasubset:a!queryEntity(
      entity:cons!EMPLOYEE_DSE,
      query:a!query(pagingInfo: local!pagingInfo)
    ),
    local!hasData: not( local!datasubset.totalCount=0 ),
    a!sectionLayout(
      contents:{
        a!buttonLayout(
          secondaryButtons:{
            a!buttonWidget(
              label:if( local!hasData , "Data Already Published" , "Publish Data" ),
              style:"PRIMARY",
              saveInto:{
                a!writeToDataStoreEntity(
                  dataStoreEntity: cons!EMPLOYEE_DSE,
                  valueToStore: local!dataToLoad
                )
              },
              disabled: local!hasData,
              submit: true
            )
          }
        ),
        a!gridField(
          label:"Data from local data subset",
          /* Show a grid from hard-coded data since nothing yet exists in the database*/
          showwhen: local!datasubset.totalCount = 0,
          labelPosition:"COLLAPSED",
          totalCount:count( local!dataToLoad ),
          columns:{
            a!gridTextColumn( label:"ID", data: repeat( count( local!dataToLoad), "N/A") ),
            a!gridTextColumn( label:"First Name", data:index( local!dataToLoad, "firstName", null) ),
            a!gridTextColumn( label:"Last Name", data:index( local!dataToLoad, "lastName", null) ),
            a!gridTextColumn( label:"Department", data:index( local!dataToLoad, "department", null) ),
            a!gridTextColumn( label:"Title", data:index( local!dataToLoad, "title", null) ),
            a!gridTextColumn( label:"Phone Number", data:index( local!dataToLoad, "phoneNumber", null) , alignment:"RIGHT" ),
            a!gridTextColumn( label:"Start Date", data:index( local!dataToLoad, "startDate", null), alignment:"RIGHT" )
          },
          value:a!pagingInfo(1,20)
        ),
        a!gridField(
          label:"Data from local datasubset",
          /* Show a grid with database data*/
          showwhen: not(local!datasubset.totalCount = 0),
          labelPosition: "COLLAPSED",
          totalCount: local!datasubset.totalCount,
          columns:{
            a!gridTextColumn(
              label: "ID",
              field: "id",
              data: index(local!datasubset.data, "id", {}),
              alignment: "RIGHT"
            ),
            a!gridTextColumn(
              label: "First Name",
              field: "firstName",
              data: index(local!datasubset.data, "firstName", {})
            ),
            a!gridTextColumn(
              label: "Last Name",
              field: "lastName",
              data: index(local!datasubset.data, "lastName", {})
            ),
            a!gridTextColumn(
              label: "Department",
              field: "department",
              data: index(local!datasubset.data, "department", {})
            ),
            a!gridTextColumn(
              label:"Title",
              field: "title",
              data: index(local!datasubset.data, "title", {})
            ),
            a!gridTextColumn(
              label:"Phone Number",
              field: "phoneNumber",
              data: index(local!datasubset.data, "phoneNumber", {}),
              alignment:"RIGHT"
            ),
            a!gridTextColumn(
              label:"Start Date",
              field: "startDate",
              data: index(local!datasubset.data, "startDate", {}),
              alignment:"RIGHT"
            )
          },
          value: local!pagingInfo,
          saveInto: local!pagingInfo
        )
      }
    )
  )
)

Test it out

  1. Click the Publish Data button. The button will stay disabled and remain disabled as long as there is employee data present in the relational database table.
    • If data already exists in the database table, you should see a button that says, 'Data Already Published'
  2. Notice the Id values went from all "N/A" to a sequential value

Notable implementation details

  • The a!forEach() function is used here to loop the dictionary of data into an array of employee data. If we were only writing one employee here or these values were coming from a cdt array (for example from a rule input of CDT array type) then a!forEach() is not necessary.
  • To avoid duplicate records, the button stays permanently disabled as long as data is present. If your interface did not need this restriction, removing the disabled parameter definition from the button would allow you to use this button again.
  • Two grids are configured in this example, but only one will ever show at a time. Instead of writing the logic in each of the grid text columns, we are showing a grid with hard-coded data when nothing is in the database table and the other grid when there is database data available.
FEEDBACK