logo

NJP

Now Experience UI Framework efforts and my experience with it. Part 2

Import · May 04, 2020 · article

So this is a continuation of my last post on this subject.

https://community.servicenow.com/community?id=community_article&sys_id=b3192261db509c90f7fca851ca961...

So been learning new things and been relearning old lessons that I had forgotten about that came back to bite me. One of these is that once I pushed my component to a Developer instance a few times I started to find that the browser was not showing the latest version. After poking at it for sometime I realized that it was because ServiceNow was not letting the browser know that it did not have the latest version of the file and I needed to clear the browser cache. That was the first knot on my forehead as I should have known better and have gotten used to not needing to do this for a while.

The second knot on my forehead came from a discrepancy in the documentation and the fact that the now-cli login command indicates it saved your the credentials once you use it. Well unthinkingly I assumed (yes I know) that it was saving the information in the "now-cli.json" file, well it does not save it there, not sure where it saved it but it does save it because I do not have to login first to use the deploy command. So the second part was the Doc's site as of this writing shows that the proxy file should have a format of

Authorization: "Basic <username:password>"

and the developer site shows

"Authorization": "Basic <Base 64 encode username:password>"

Well I know that the two sites are not the same and did not think to check the dev site and spent a bunch of time wondering why I had an authentication error. I am here to say the Dev site is correct, you have to make sure its a base64 encoded string. I would have preferred it was encrypted but its not. So a quick google and there is an easy way to do this. Just open a browser and then open the dev tools for said browser and you can do the following using the console.

btoa("userName:password")
Result: dXNlck5hbWU6cGFzc3dvcmQ=

atob("dXNlck5hbWU6cGFzc3dvcmQ=")
Result: userName:password

So just toss the result into the Authorization line of the now-cli.json and you are off and running when it comes to getting data from the instance you specified.

After getting the proxy file straitened out getting data from an instance is supper easy. Here is an example that works using a developer instance.

import {createCustomElement, actionTypes} from '@servicenow/ui-core';
import snabbdom from '@servicenow/ui-renderer-snabbdom';
import styles from './styles.scss';
import {createHttpEffect} from '@servicenow/ui-effect-http';

const {
        COMPONENT_CONNECTED, 
        COMPONENT_ERROR_THROWN,
    } = actionTypes;

const GET_INCIDENTS_REQUESTED = 'GET_INCIDENTS_REQUESTED',
    GET_INCIDENTS_REQUEST_STARTED = 'GET_INCIDENTS_REQUEST_STARTED',
    GET_INCIDENTS_SUCCEEDED = 'GET_INCIDENTS_SUCCEEDED',
    GET_INCIDENTS_FAILED = 'GET_INCIDENTS_FAILED'
    ;

const getIncidents = createHttpEffect('/api/now/table/:table', {
    method: 'GET',
    pathParams: ['table'],
    queryParams: [
                    'sysparm_query',
                    'sysparm_display_value',
                    'sysparm_exclude_reference_link',
                    'sysparm_suppress_pagination_header',
                    'sysparm_fields',
                    'sysparm_limit',
                    'sysparm_view',
                    'sysparm_no_count'
                ],
    startActionType: GET_INCIDENTS_REQUEST_STARTED,
    successActionType: GET_INCIDENTS_SUCCEEDED,
    errorActionType: GET_INCIDENTS_FAILED
});

const view = (state, {updateState}) => {
    return (
        <div>
        </div>
    );
};

createCustomElement('x-8781-incident-viewer', {
    renderer: {type: snabbdom},
    view,
    styles,
    actionHandlers: {

        //Component actions **********************
        [COMPONENT_CONNECTED]: {
            effect({state, properties, action: {payload: {host}}, updateState, dispatch}){
                dispatch(GET_INCIDENTS_REQUESTED, {
                    table: 'incident',
                    sysparm_query: '^table_sys_id=',
                    sysparm_fields: 'sys_id',
                    sysparm_limit: 3,
                    sysparm_display_value: 'true'
                });

            }
        },

        //Get Image action handlers **********************
        [GET_INCIDENTS_REQUESTED]: getIncidents,
        [GET_INCIDENTS_SUCCEEDED]: ({action}) => {
            if(action.payload.result && action.payload.result.length > 0){
                action.payload.result.forEach(element => {
                    console.log(element.sys_id)
                });
            }
        },
        [GET_INCIDENTS_FAILED]: () => {

        },

        //Error Handeling **********************
        [COMPONENT_ERROR_THROWN]: ({action: {payload}}) => {
            console.log(payload)
        }
    },
    properties: {
        table: {
            default: null
        },
        sysId: {
            default: null
        }
    }

});

So the code is fairly simple but once you start getting into multiple components you need to pay attention to the action type strings you use. As far as I can tell these are global, so when you do a dispatch if there is another component on the page that uses the same string then it will react, which is a good thing but if you are not paying attention you could have duplicate string being used and get undesired affects. So make sure your constant's are as unique as you can make them.

Another item is there have been a number of times where I have wondered what parms do I need or are available for an action handler since they are not clearly documented. Well I have found a relative easy way to find out. Consider this code, it will error because dispatch is not defined.

        [COMPONENT_CONNECTED]: {
            effect({state, properties, action: {payload: {host}}, updateState}){
                dispatch(GET_INCIDENTS_REQUESTED, {
                    table: 'incident',
                    sysparm_query: '^table_sys_id=',
                    sysparm_fields: 'sys_id',
                    sysparm_limit: 3,
                    sysparm_display_value: 'true'
                });

            }
        },

So if you are wondering were to get it. you can just do this

        [COMPONENT_CONNECTED]: {
            effect({...stuff}){
                console.log(stuff);
            }
        },

So what this will do is assign all of the parameters to the var stuff and once you dump it to the console you can then pick thru it and see whats there and what you need to pull out.

Next lets take a look at the properties that I added. This is something that came out in some example components posted to the ServiceNowDevProgram on GitHub

https://github.com/ServiceNowDevProgram/now-experience-component-examples

This was something I was happy to see and so with this there is the question of are there more. Well there are. You can see them by going to an instance on Orlando then "Workspace Experience -> Contextual Side Panel" and then just pick any record and you will see a related list called "Action Model Fields".

image

So now we have a list of properties that we can add to our components to connect it to other things on the page. One thing to keep in mind as far as I can tell is that they are case sensitive so if one does not look like its working check the case.

So whats next? Well as I understand it bootstrap is not available and ServiceNow planes to create there own components that will take the place of the bootstrap items. So it looks like we will see about 30+ components from them per family release but until then I need something to save my sanity. So this is how you can install bootstrap.

npm install bootstrap

Docs

https://www.npmjs.com/package/bootstrap#quick-start

Not sure this will be a good idea but going to try it and see if it works and does not blowup.

Thoughts? Questions? Comments? Please post below.

View original source

https://www.servicenow.com/community/developer-articles/now-experience-ui-framework-efforts-and-my-experience-with-it/ta-p/2322120