Updating a record in a service portal widget

martinsk
Mega Expert

Hi

I'm in need of some help with a service portal widget. Here's what I've got so far: the widget displays a list of assets issued to the current user (using a glide record in the server script and ng-repeat in the HTML template). For each asset listed, I've also got a button which doesn't do much at the moment other than display a message (just to prove the click works).

What I want is for the user to be able to click the button along side a particular asset, to confirm they still have it, and for this to update the status / last confirmed date in the respective asset record.

Please can someone confirm the syntax:

  1. in the HTML template, to pass the sys_id back to the client script (via ng-click?)
  2. in the client script, to grab the sys_id and pass it on to the server script (via a function and c.server.update?)
  3. in the server script, to get the sys_id and update a glide record for the correct asset (via input?)

Thanks in advance.

Martin 

1 ACCEPTED SOLUTION

matthewmaxwell
Kilo Guru

If you're using an ng-repeat with the buttons inside (I assume you are), you have access to the current model that you can pass into the ng-click, like this:

<div ng-repeat="asset in controller.assets">
  <button ng-click="confirmAsset(asset);">Confirm!</button>
</div>

In your controller's ng-click handler (I named it confirmAsset here), you would do something like this:

// This is the confirmAsset method on your controller
this.confirmAsset = function(asset) {
    // Asset is being bassed from the ng-click
    // The controller has a server property with a method called get on it.
    // The object you pass to the get() call is passed as "input" on the server-side code.
    this.server.get({
        // NOTE: This method property is totally unneeded technically.
        //  I am adding it here so that my server-side code can know exactly what it's supposed to do.
        method: "confirmAsset",
        asset_sys_id: asset.sys_id
    });
}

The server side script would do something like this:

if (input) {
    // Adding a method here just in case anything else sends information to the
    // client side script, we can distinguish and only handle what we need to.
    if (input.method === "confirmAsset") {
        // NOTE: tableName here should be the name of the table
        var record = new GlideRecord(tableName);
        // NOTE: asset_sys_id should be the name of the field you want to update for
        //  confirmation
        record.addQuery("asset_sys_id", input.asset_sys_id);
        record.query();
        if (record.next()) {
            // NOTE: Set whatever field you're using to confirm the asset
            record.confirmed = true;
            // Update the record.
            record.update();
        }
    }
}

Hope this helps.

View solution in original post

25 REPLIES 25

"asset_sys_id" is just the name of the property of the object I am sending over. Its value is "asset.sys_id", which is the sys_id of the asset at the current iteration. That asset is an object. You may replace that label with anything you'd like. I've simply named it that because that property name reads well to me and lets me know what the value contains.

Hello, 

 

Wondering if you can help, I am trying to implement the above. 

 

Requirement - when a widget is clicked on the ESC, it counts the clicks. Specifically using the Quick Link widget (or a customised variation of the widget).

Based on the above I have added this to the HTML:

MichaelCreatura_0-1709640257878.png

This to the server script:

MichaelCreatura_1-1709640296884.png

 

This to the client controller: 

MichaelCreatura_2-1709640341491.png

 

As you can see in the Server Script, I have created a new table and referenced it where required, but do I need to add anything else too it? 

 

MichaelCreatura_5-1709640455463.png

Any help appreciated! 

Hi Michael,

 

Can you give me the exact widget name you're trying to modify? Because this post was originally around assets, I would change some of the variable names to match, and I also suspect that the widget may have an ng-repeat already present that we can drop our code into.

 

If you'll provide the name of the widget, I can adjust the above example to be better suited for that use case.

 

m

Hi @matthewmaxwell,

 

It's a duplicate of the Quick Links widget called "Service Catalog (service_Catalog)", the only alterations are some minor formatting, CSS changes. 
Thanks, 


Hey Michael,

 

I was able to get a working example of this.

 

I created a custom table, as you did here with the same name.

 

I cloned the Quick Links widget, and made the following changes:

 

Because there are multiple links in the widget, I opted to leverage event delegation, so in the Widget Link field, I added the following code:

 

element.on("click", ".link-container a", function (event) {
    // Use event delegation so there is only a single DOM event instead of n, where n would be the numebr of quick links
    var link;
    var itemId;

    // This would be the anchor tag, but because events bubble, this could be the span if they clicked the text
    link = event.target;

    // If the link is not an anchor tag, find the nearest parent element that is an anchor tag
    if (link.nodeName !== "A") {
        link = $(link).parents("a").get(0);
    }

    // There is no error handling here, so this may need to be fleshed out a little more
    // ID will be a sys_id plus the item-n where n is the index in the array
    // Example: "2fd7d372775530104cdac0c23e5a9953-item-0"
    // This will replace "2fd7d372775530104cdac0c23e5a9953-item-" with nothing and give us the number
    itemId = link.getAttribute("id").replace(/\w+-item-/, "");
    controller.recordClick(controller.data.json_data[itemId]);
});

 

This sets up event delegation to listen for click events on the anchor tags in the link container. I used this method because there are multiple links and because there are multiple different ways that those links display, which you can see by looking at the HTML Template for the `c.data.card_type` checks in the `ng-if`s.

 

Because events bubble, if someone clicks on the text in the link (the Span node), this will not be the anchor tag, which contains the information we need, so we find the closest parent using `$(link).parents("a")`.

 

The links have an `id` attribute that is `sys_id-item-index_in_array`. In the second to last line, we get rid of the sys_id, the hypens, and the word `item`, and use that index in the last line to look up the actual link object in the controller data and then pass that into a method I added to the controller.

 

In the controller, I added the following method:

 

c.recordClick = function (link) {
    this.server.get({
        method: "recordClick",
        link_sys_id: link.id
    });
};

 

This method will take the link and pass its sys_id to the Server Script.

 

In the Server Script, I declared a `linkClick` variable at the very top because I like to declare all my variables at the top of the scope, so the definition is not in the following code, but here is the code that records the click into the table:

 

if (input && input.method === "recordClick") {
    linkClick = new GlideRecord("sn_ex_sp_employee_service_center_clicks");
    linkClick.initialize();
    linkClick.setValue("u_quick_link", input.link_sys_id);
    // This console.log should be removed before this goes to production
    console.log("Created: " + linkClick.insert());
}

 

For that table, I did add a single field which is a reference to the quick link table.

 

Now, when I click the link, I see the following in that table:

 

matthewmaxwell_0-1709649942552.png

 

I am attaching an update set that has this in it. If you put this in a fresh PDI, you should see everything there.

 

Let me know if you have any other questions.

 

m