Walking through the Developer MVP Directory (LCHH Part 1 & 2)



This post will go through what we're doing and what we've done so far on Live (Lady) Coding Happy Hour for the Developer MVP Directory app.


You can watch Part 1 and 2 here, and I'll create a new post once we finish the app with Part 3. Thank you to the ServiceNow Developer Advocate program for letting us take over and shining a spotlight on female-identifying developers in the ServiceNow space. I also want to give a shout out to everyone who helped with the LCHHs:


Brad Tilton

Chuck Tomasi

Maria Gabriela Ochoa Perez Waechter

Paige Duffey

Nia McCash


Also here's a plug for the WomenNow blog which you can find Maria, Paige, and Nia posting on, and has a lot of great posts not only technically related but also about female-identifying experiences in the ServiceNow space as well.


Part 1


Developer MVP Table


This table was kept intentionally simple, we just loaded some basic data we got in from the Developer MVPs. During Part 1, we extended sys_user, but received some feedback on the approach, so behind the scenes we created a new table that referenced sys_user with the Name field instead.


Fields:


Fun Fact 1 (String)

Fun Fact 2 (String)

Fun Fact 3 (String)

Website (String)

Social Media (String)

Bio (String - 4000 characters max)

Name (Reference to sys_user)

Name.Photo (Dot walking to sys_user)


Portal Experience


Next we created a Portal experience from scratch by navigating to Now Experience Framework > Experiences.



To create the Portal experience we used the Portal App Shell for the App Shell UI, and set up a UX App Configuration in the Admin panel.



Then we created a chrome_header UX Page Property to create a header for the portal experience.



JSON:

{
    "privatePage":{
    "searchEnabled": false,
        "userPrefsEnabled":true,
        "currentScreenLinkConfiguration": {
        "roles": ["admin"],
            "position": 250
    },
    "globalTools":{
        "collapsingMenuId":0,
            "primaryItems":[
            {
                "label":"UserMenu",
                "icon":"user",
                "type":"menu",
                "primaryDisplay":"icon",
                "value":{
                    "children":[
                        {
                            "label": {
                                "translatable": true,
                                "message":"Settings"
                            },
                            "position":100,
                            "type":"navigation",
                            "value":{
                                "type":"route",
                                "value":{
                                    "route":"settings",
                                    "fields":{

                                    }
                                }
                            }
                        },
                        {
                            "condition": {
                                "roles": ["admin", "ui_builder_admin"]
                            },
                            "label":{
                                "translatable": true,
                                "message":"Configure"
                            },
                            "type":"navigation",
                            "position":200,
                            "primaryDisplay":"none",
                            "value":{
                                "type":"external",
                                "opensWindow":"true",
                                "value":{
                                    "href":"/nav_to.do?uri=/sys_ux_app_config.do?sys_id=[SYS_ID OF YOUR UX APP CONFIG]"
                                }
                            }
                        },
                        {
                            "label": {
                                "translatable": true,
                                "message":"Logout"
                            },
                            "position":500,
                            "type":"navigation",
                            "value":{
                                "type": "AUTH_ROUTE_BINDING",
                                "binding": {
                                    "address": ["logout"],
                                    "params": {"reload": true},
                                    "default": "/logout.do"
                                }
                            }
                        }
                    ]
                }
            }
        ],
            "secondaryItems":[]
    }
},
    "publicPage":{
    "menuEnabled": true,
        "logoRoute": {
        "type": "route",
            "value": {
            "route": "landing",
                "fields":{}
        }
    }
}
}

We then created the chrome_menu UX Page Property to create a clickable link to the Game we'll create in Part 3.



JSON:

[{
    "value":{
        "label":{
            "translatable":true,
            "message":"Play the Developer MVP Game"
        },
        "target":"",
        "type":"route",
        "value":{
            "route":"game"
        }
    }
}]

Landing Page/Data Set


Next we placed a Data Set component on our Landing/Home page. Here are the options we configured:


Title: Developer MVP Directory

Default view: Grid

Hide Filter: True


EVAM Definition


EVAM or Entity View Action Mapper is a data resource that can be used to display data within data set components. Our use case was pretty simple because we're just showing data from one table, but EVAM can be used to get and show data from multiple tables/data sources and configure multiple views of that data.


First, we created a EVAM Definition (Entity View Action Mapper (EVAM) > EVAM Definition) called Developer MVP.



Next we created an EVAM Datasource M2M by clicking Create and Link on the related list.


Name: Developer MVP DS

Table: [Our Dev MVP table]

Sort by: Created


The condition field is where you can filter out what data should be returned, for our use case we wanted to return all records, so this was left blank.



Next we created an EVAM View Config Bundle named Developer MVP VCB by clicking Create and Link on the related list.



We added a EVAM View Config on the related list named Developer MVP VC and added the fields we wanted to get from the Developer MVP table.



The last two things that needed to be done on the EVAM Definition was to configure the View Template named Developer MVP VT which is referenced on the EVAM View Config record, here's the JSON we used, but there is a template example when creating a View Template that you can use you configure your values:


{
    "component": "now-card-evam-record",
    "staticValues": {
    "highlightedHeaderIcon": {
        "translatable": false,
            "key": "clock-outline"
    },
    "highlightedHeaderBkgColor": {
        "translatable": false,
            "key": "moderate"
    },
    "imageType": {
        "translatable": false,
            "key": "avatar"
    },
    "detailLabelOne": {
        "translatable": true,
            "key": "website"
    },
    "detailLabelTwo": {
        "translatable": true,
            "key": "social_media"
    },
    "detailLabelThree": {
        "translatable": true,
            "key": "bio"
    }
},
    "mappings": {
    "highlightedHeaderLabel": "",
        "textHeaderLabel": "",
        "titleLabel": "name",
        "avatarURL": "name.photo",
        "subtitle": "",
        "subtitleAvatarName": "",
        "subtitleAvatarURL": "",
        "detailValueOne": "website",
        "detailValueTwo": "social_media",
        "detailValueThree": "bio"
},
    "actionMappings": {
    "mainActions": ["activate_user", "call_number"],
        "clickAction": "navigation"
}
}

The final step is to link an EVAM View Config Action Assignment M2M to the EVAM View Config record by clicking Create and Link.


Here we're creating an Action Assignment, and calling the navigation client action already created by ServiceNow in the Specify client action field. This should also be implemented as UXF Client Action so it will apply to Now Experiences.


Here's what the record looks like after the Action Assignment has been created and linked:



Data Resource


Now that we have our EVAM Definition set up, we need to call it on our Home page in order to link it to our Data Set component. This is done by setting up a Data Resource on the page. To get to Data Resources for a page, click on the icon at the bottom left that looks like a database or stack of discs, and click the +Add button. From there you can navigate to Global > EVAM Data Resource > and click Add. We configured the EVAM Definition to point to the one we created above.



Next, we linked the Data Set component with the Data resource by calling it in the Data field: @data.evam_data_resource_1.compositeDataViews



Theme


The last thing we did in Part 1 was create and add a Theme to our experience by navigating to Now Experience Framework > Themes and creating a theme with some basic CSS Variables:


{
    "--now-color--primary-1": "180,142,173",
    "canvas-header-container--background-color":"180,142,173",
    "--now-color--primary-0": "143,188,187"
}

We also added an icon to the Portal by adding a UX Theme Asset, and giving it the Asset Properties of {"position":"header_logo"}


We then linked the theme to the experience in UI Builder by navigating to Menu > Edit Experience Settings > Branding and theming > and selecting our theme.


Here's the end result from Part 1:



Part 2


Our goal for Part 2 was to link the Data Set component and Info page together so when a card is clicked, it goes to the user's record in the Info page. This session was fun because we got to break stuff along the way, and discuss the concept of versioning pages, which I hadn't thought about before when using UI Builder. Also, we provided insight on as to why two developers may run into difficulties when working on the same page at the same time. ^_^


Info Page


We created an Info page and started populating a layout with components such as the Avatar component, Heading components, and stylized text component. Basically configuring container components with layouts and adding more container components within them.


Home Page Events


Next we set up some events on the home page to connect both together. We created a Handled event called Open MVP and assigned it a Payload field of sysId.



Then we set up a Link to destination Page event mapping on the home page and configured it to route to the info page, and pass @payload.sysId



I'll go ahead and call this out here, even though we haven't done it yet and was something I missed in Part 2 which kind of tripped me up a bit, but the last thing we need to do on the Home page is link up the Event we just created to the Data Set component. This is done by clicking Configure declarative action event mappings in the Data Set component configuration panel.




So again, this isn't in the video, but will be done during Part 3 to finish up this part of the experience mapping.


Data Resource


Before we finished adding more headers/text to the page, we linked up a Data Resource to grab the fields that were needed. Same as we did on the homepage, click the Database icon on the bottom left click Add+, Global > GlideRecord Query > Add. We then gave the object an ID, which is important in the Scripted property we'll be calling in a moment, set the table to our Dev MVP table, passed in @context.props.sysId for the Record, which is basically grabbing the sysID from the URL (which is the payload we're passing in the Link to Destination event we configured on the Home page) and returned the fields we wanted.



Data Binding to Component


Now that we have our data, we can bind what we need to each Stylized Text component we put in. In the video, I used a Scripted Property Value and passed the following, modifying the field name for each section.


/**
 * @param {params} params
 * @param {api} params.api
 * @param {any} params.imports
 */
function evaluateProperty({api}) {
    return api.data.mvpObj.output.data.GlideRecord_Query.x_238775_develop_0_dev_mvp._results[0].name.displayValue;
}

In the LCHH I linked up the Stylized text components I needed with this script and the values I needed for each component.




UX Macroponent Definitions/Versioning


I wanted to mention this here because it is an important concept and was mentioned during the video. In order to revert some of the issues we had during the LCHH, Maria added the Versions related list to the sys_ux_macroponent page. Each page in UI Builder is stored in a record in this table. The layout of your page, Data resources, events, properties, etc. are stored in this record. Basically everything you see in UI Builder for a page is stored in here JSON format. I'm not going to tell you if you should ever touch this or not (I have and broke stuff ^_^ in a PDI) but it's important to know. If needed, you can always revert to a version of your page here, which doesn't seem to be an option in UI Builder as of the Quebec release.



Part 3


So, we do have some work cut out for us in Part 3, as we may be switching up our approach regarding a Data Resource on the Info page since GlideRecord doesn't seem like it supports dot walking fields at this moment, in order to pass the Photo field from the sys_user record to the Avatar component on the Info page.


We'll add the Declarative event mapping I mentioned above to finalize the linking of the Data Set component to the Info page.


And finally create a Game page to plugin a quiz about the Developer MVPs into, that can be taken directly on the Portal itself.


I hope this step by step guide helped in following along with the LCHH videos and explained what we were doing and why. I've also linked some great resources below on EVAM that I used in my learning before doing the LCHH.


Resources


ServiceNow Developer Blog - UI Builder - EVAM Data Resources

ServiceNow Product Documentation - Entity View Action Mapper

148 views0 comments

Recent Posts

See All