- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-27-2018 07:42 AM
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:
- in the HTML template, to pass the sys_id back to the client script (via ng-click?)
- in the client script, to grab the sys_id and pass it on to the server script (via a function and c.server.update?)
- in the server script, to get the sys_id and update a glide record for the correct asset (via input?)
Thanks in advance.
Martin
Solved! Go to Solution.
- 12,380 Views
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-28-2018 12:34 PM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-28-2018 12:34 PM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-29-2018 01:25 PM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-29-2018 03:14 PM
Absolutely. In order to explain this, I'll explain a few clarifying things first (I apologize if you already know this, but I want to make sure it's clear). A Service Portal widget is actually is an Angular directive that has been broken up into individual pieces on the ServiceNow platform. Angular will insert the HTML in the template into the DOM and then it will run a compiler against it. When this happens, Angular will two-way bind your controller to the view (the HTML template). This means that whenever the controller has a value change and a digest cycle is run (after an ng-click, for example), the view is updated to reflect the new values.
ng-repeat is a built-in Angular directive that iterates over an iterable property of your controller (an array is most common, but it can also be an object) and repeats the node that the ng-repeat is on as well as any child nodes inside of it for every iteration. When ng-repeat runs, you are creating a variable that is local to the loop that represents the current iterable value for that loop. For example, in ng-repeat="asset in controller.assets", you are doing a loop over the property of your controller called assets and during the ng-repeat, you have access to asset, which is the current value of the loop.
ServiceNow has created a server property on every controller that has a get method on it. That get method will do a POST request to /api/now/sp/widget/<sys_id_of_the_widget>. sys_id_of_the_widget can be found at this.widget.sys_id in your controller, if you're curious. That is how the server-side script gets the POST HTTP request, and the response of that request is passed back. If you wanted the result, you would use a then() call on the this.server.get(). (I can show you that if you're interested, but essentially this.server.get() returns a promise, if you're familiar with those).
With that in mind, here is a cradle-to-grave analysis of what is happening.
1. Controller property is set to array of assets.
2. ng-repeat creates a copy of the DOM structure for the directive's root node and any child nodes.
3. ng-repeat two-way binds the current value to the DOM structure and appends it to the node containing the ng-repeat.
4. ng-click directive runs and binds a click handler to the button. The current value in the loop is passed in to the handler created, so that it is retained via closure.
Now the DOM has been created with the handler bound. When the user clicks the button:
1. onclick handler of the button fires, and the value for that handler is passed into the handler, e.g. confirmAsset(asset)
2. this.server.get() is called passing the asset_sys_id to the server-side script.
3. Server-side script is called with a global "input" variable created. This "input" variable represents data passed to the server. The object passed to this.server.get() is what "input" is.
4. You do whatever you need to with the data.
5. You can return a value (object, string, number, array) in the server-side function, which is passed back to the client side.
6. The http promise resolves, and if you have a fulfillment handler registered it is called and the value passed into it.
Hopefully that helps you understand what's going on.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎04-30-2018 01:35 AM
That's excellent. Very helpful. Just one thing: 'asset_sys_id' (in the client script) obviously refers to the sys id of the asset, but how is it derived? Is it a name I need to replace with something else?
Thanks again.
Martin