Skip to content

Instantly share code, notes, and snippets.

@wave-inguane
Last active October 8, 2021 15:10
Show Gist options
  • Save wave-inguane/d0258d840816358ea9b35c02412f9abd to your computer and use it in GitHub Desktop.
Save wave-inguane/d0258d840816358ea9b35c02412f9abd to your computer and use it in GitHub Desktop.
Notes
function ($scope, $rootScope, $timeout, spUtil,spModal, $location, $window, nowAttachmentHandler, $log, spAriaUtil) {
var url = $location.absUrl();
$timeout(function() {
if (g_form) {
g_form.submit(action.action_name || action.sys_id);
if(url.indexOf('x_smart_selection_sf_rank') != -1){
$window.open('/selection?id=sel_dash','_self');
}
}
});
}
}
function($scope, $location) {
/* widget controller */
var c = this;
var url = "/$pwd_reset.do?sysparm_url=ss_default";
for (var key in urlParams) {
if (key == 'sysparm_redirect_url')
url += '&sysparm_redirect_url=' + urlParams[key];
if (key == 'sysparm_show_custom_header_footer')
url += '&sysparm_show_custom_header_footer=' + urlParams[key];
}
$scope.iframeUrl = url;
}
<div>
<button type="button" class="btn btn-primary" ng-mousedown="c.handleEvent($event);" ng-mouseover="c.handleEvent($event);" >Primary</button>
</div>
<div ng-mouseleave="handleEvent2($event)"> </div>
api.controller=function($scope, spUtil) {
/* widget controller */
var c = this;
//ng-mousedown="handleEvent($event)"
c.handleEvent = function (e) {
if(e.type == "mousedown"){
//spUtil.addInfoMessage("here: "+ e.type);
var done = '<p class="text-center text-primary">'+ "here: "+ e.type +'</p>';
spUtil.addInfoMessage(done);
}
if(e.type == "mouseover"){
// spUtil.addInfoMessage("here: "+ e.type);
}
}
//usage in
//<div ng-mouseleave="handleEvent($event)"> </div>
//-----------------------------------------------
// To be used during development test phase only
// Provides impartial feedback on new features
//-----------------------------------------------
$scope.handleEvent2 = function (e) {
//use in footer
//Triggered when the pointer is moved to be within the screen region occupied by
//the element or one of its descendants.
if(e.type == "mouseenter"){
}
//use in live chat
//Triggered when the mouse button is pressed.
if(e.type == "mousedown"){
}
//use on thumbs
//The same as for mouseenter, except that this event will trigger while the pointer is
//still over a descendant element.
if(e.type == "mouseover"){
}
// use in serch area
//Triggered when the pointer is moved to be outside the screen region occupied
//by the element and all its descendants.
if(e.type == "mouseleave"){
}
//Triggered when the pointer is moved while over the element.
if(e.type == "mousemove"){
}
//The same as for mouseleave, except that this event will trigger while the pointer is
//still over a descendant element.
if(e.type == ""){
}
//Triggered when the mouse button is released.
if(e.type == "mouseup"){
}
}
};
/*
$rootScope.$on('action_data', function(event,actionData) {
if((actionData.action_request == "report_submit") &&
(actionData.item_id == "-1") &&
(actionData.parent_table == "") &&
(actionData.table_name == "")){
c.server.get({
action: 'submitToCC',
SysID: actionData.item_id
}).then(function(res) {
var r = res.data.canSubmit;
if(r == false || r =="false"){
var done = '<p class="text-center text-primary">'+ 'Please Save as Draft' +'</p>';
spUtil.addInfoMessage(done);
return;
}
});
}
});
*/
//=================================================================================================================================
// Notes Body
//=================================================================================================================================
<div class="panel panel-default" ng-show="c.data.noteID">
<div class="panel-heading clearfix">
<div class="row">
<div class="col-md-11">
<input class="form-control" id="note-title" ng-model="c.data.title" ng-change="c.updateNote('title')" ng-model-options="{debounce: 1000}"/>
</div>
<!--
<div class="col-md-1">
<button class="btn btn-danger pull-right" ng-click="c.confirmDelete()">
<span class="glyphicon glyphicon-trash"></span>
</button>
</div>
-->
<!-- USE CUSTOM DIRECTIVE -->
<delete-button-confirm></delete-button-confirm>
</div>
</div>
<div class="panel-body">
<textarea class="form-control" id="note-body" ng-model="c.data.note" ng-change="c.updateNote('body')" ng-model-options="{debounce: 1000}" ></textarea>
</div>
</div>
//============================================================================================================================
//
//============================================================================================================================
function($scope,$rootScope,spUtil,spModal) {
/* widget controller */
var c = this;
/*
$rootScope.$on('selectNote2', function(event,data) {
console.log('Listener caught NoteID-2: ' + data.sys_id);
});
*/
//CRUD-OPERATIONS
//----------------------------------------------------------
// CREATE
//----------------------------------------------------------
$rootScope.$on('selectNote', function(event,myData) {
console.log('Listener-1 caught NoteID: ' + $rootScope.noteID);
console.log('Listener-x caught NoteID: ' + typeof myData);
console.log('Listener-2 caught NoteID: ' + myData);
console.log('Listener-3 caught NoteID: ' + $rootScope.myJson.sys_id);
//-----------------------------------------------------------
// READ
//-----------------------------------------------------------
c.server.get({
action: 'getNote',
noteID: $rootScope.noteID
}).then(function(r) {
c.data.title = r.data.note.title;
c.data.note = r.data.note.note;
c.data.noteID = r.data.note.sys_id;
});
});
//-----------------------------------------------------------
// UPDATE
//-----------------------------------------------------------
c.updateNote = function(updateType) {
c.server.get({
action: 'updateNote',
noteID: c.data.noteID,
noteBody: c.data.note,
noteTitle: c.data.title
}).then(function(r) {
//Notify the user of the outcome of the action
});
}
//-----------------------------------------------------------
// DLETE
//-----------------------------------------------------------
c.deleteNote = function() {
c.server.get({
action: 'deleteNote',
noteID: c.data.noteID
}).then(function(r) {
spUtil.addTrivialMessage("The " + c.data.title + " record has been deleted.");
$rootScope.$emit('deleteNote', c.data.noteID);
c.data.title = '';
c.data.note = '';
c.data.noteID = '';
});
}
c.confirmDelete = function(){
spModal.confirm('<p class="lead">'+'<center>'+"Are you sure you want to delete this Note record ?"+'</center>').then(function(confirmed){
if(confirmed){
c.deleteNote();
}
});
}
}
//============================================================================================================================
//
//============================================================================================================================
(function() {
/* populate the 'data' object */
/* e.g., data.table = $sp.getValue('table'); */
/*
Question: Recall that only Notes records for the currently logged in user are displayed in the Notes List widget. How is the User value set on the new Notes records?
Answer: There are a few different strategies one could use to set the User value for new Note records including:
Set the value in the widget's Server-side script
Set the value using a before Business Rule for record inserts
Set a default value in the User field's Dictionary Entry
The drawback to using the Server-side widget script is that if users use the CreateNotes > Notes module to create a new record, the User field value must be manually set. The benefit to using this strategy is that the logic exists in the Widget itself and is easy to find.
The drawback to using a before Business Rule is that you have another application file to maintain and you, the developer, have to remember not all of the logic for your application is in the widget scripts.
The drawback to setting a default value in the User field's Dictionary Entry is that you have to remember you did that. You can see the field's default value in the Table record but you have to remember to look there.
The Dictionary Entry default value is how the User field is set in the CreateNotes application you loaded from the GitHub repository for this exercise.
*/
if (input && input.noteID) {
var note = new GlideRecord('x_snc_createnotes_note');
if (note.get(input.noteID)) {
//-----------------------------------------------------------
// READ
//-----------------------------------------------------------
if (input.action == 'getNote') {
data.note = {};
$sp.getRecordValues(data.note, note, "title, note, sys_id");
}
//-----------------------------------------------------------
// UPDATE
//-----------------------------------------------------------
else if (input.action == 'updateNote') {
note.title = input.noteTitle;
note.note = input.noteBody;
var f = note.update();
// Need to update the data object with the new title
// and first 20 characters of the note (do not want to write huge
// strings to the Notes List widget)
//if(f){
data.title = note.getValue('title');
data.note = note.getValue('note');//.slice(0,20);
//}
}
//-----------------------------------------------------------
// DLETE
//-----------------------------------------------------------
else if (input.action == 'deleteNote') {
note.deleteRecord();
}
}
}
})();
//=================================================================================================================================
// Angular provider
//=================================================================================================================================
// Type: Directive
// Name deleteButtonConfirm
//Client Script:
function(){
return{
template: '<div class="col-md-1"><button class="btn btn-danger pull-right" ng-click="c.confirmDelete()"><span class="glyphicon glyphicon-trash"></span></button></div>',
restrict: 'E'
};
}
//=================================================================================================================================
// Notes List
//==============================================================================================================================
<div class="panel panel-default">
<div class="panel-heading clearfix">
<h3 class="panel-title pull-left">
<!--${Notes}-->
{{::c.options.title}}
</h3>
<button class="btn btn-default pull-right" ng-click="c.newNote()">
<span class="glyphicon glyphicon-plus"></span>
</button>
</div>
<div class="panel-body">
<input placeholder="Filter" class="form-control" ng-model="noteFilter" />
</div>
<div class="list-group">
<a class="list-group-item" ng-click="c.selectItem($index)" ng-repeat="note in data.notes | filter: noteFilter">
<h4 class="list-group-item-heading">
{{note.title}}
</h4>
<p class="list-group-item-text">
{{note.note}}
</p>
</a>
</div>
</div>
//=================================================================================================================================
// Clent script
//=================================================================================================================================
function($rootScope,$scope,spUtil) {
/* widget controller */
/*
Client-side API
The client-side Widget API classes are:
spUtil: Contains utility methods to perform common functions in a Service Portal widget client script. Access the methods from this class using spUtil. For example, spUtil.addErrorMessage().
addErrorMessage(): display an error message
addInfoMessage(): display an informational message
addTrivialMessage(): display a message which automatically disappears after a short period of time
format(): used to build strings from variables (alternative to concatenation)
get(): gets a widget model by ID or sys_id
recordWatch(): watches for updates to a table or filter and returns the value from a callback function
refresh(): calls the server and replaces the current options and data objects with the server response
update(): updates the data object on the server within a given scope
spModal: Methods provide an alternative way to show alerts, prompts, and confirmation dialogs. Access the methods from this class using spModal. For example, spModal.alert().
alert(): displays an alert
confirm(): displays a confirmation message
open(): opens a modal using the specified options
prompt(): displays a prompt for user input
spAriaUtil: Uses an AngularJS service to show messages on a screen reader. Access the method from this class using spAriaUtil. For example, spAriaUtil.sendLiveMessage().
sendLiveMessage(): announce a message to a screen reader
For the complete API documentation, including method arguments and return values, follow the links to the API classes.
Client-side Debugging
The client-side Widget API includes methods which can be used for logging/debugging:
spUtil.addErrorMessage()
spUtil.addInfoMessage()
spUtil.addTrivialMessage()
spModal.alert()
Using the Client-side Widget API
In an earlier part of this module, you learned there are three client-side Widget APIs:
spUtil: Contains utility methods to perform common functions in a Service Portal widget client script.
spModal: Methods provide an alternative way to show alerts, prompts, and confirmation dialogs.
spAriaUtil: Uses an AngularJS service to show messages on a screen reader.
In order to use classes from the client-side Widget API, the global object for the API must be passed as a dependency to the Client Script. The Client Script creates the AngularJS controller using the passed in dependencies.
If a Client Script attempts to use a client-side Widget API without passing the dependency, a ReferenceError occurs at runtime.
Using AngularJS Events with Widgets
AngularJS uses a publish and subscribe strategy for handling events. Events are useful for notifying widgets about important things happening in other widgets. For example:
Record selected
Changed value
Data deleted
Data added
And more....
Work with events in AngularJS using these functions:
$emit(): Send an event up the scope hierarchy
$on(): Listen for events of a given type
DEVELOPER TIP: Avoid the use of $rootScope.$broadcast() because it can cause performance issues.
$rootScope.$emit("eventName",{})--event-->$rootScope---event-->$rootScope.$on("eventName", function(event, dada)){}
recordWatch()
In the CreateNotes widgets, you are able create, update, and delete Notes records. What happens in the widgets if a
user creates a record using the standard ServiceNow UI (UI16)?
Although the Notes List and Notes Body widgets have been developed to communicate with each other,
they are not notified of changes made to the Create Notes table records when the interaction happens
through the standard ServiceNow UI.
Use the Client API method spUtil.recordWatch() to register a listener in a widget. The listener is
notified when table records are inserted, deleted, or updated
spUtil.recordWatch($scope, "table_name", "filter", function(name) {
console.log(name); //Returns information about the event that has occurred
console.log(name.data); //Returns the data inserted or updated on the table
});
}
spUtil.recordWatch($scope,"incident","active=true",function(name){
// listen for changes to incident table records where the record is active i
console.log(name); //Returns information about the event that has occurred
console.log(name.data); //Returns the data inserted or updated on the table
});
}
//GET QUERY FROM QUERY BUILDER
spUtil.recordWatch($scope,"incident","caller_idDYNAMIC90d1921e5f510100a9ad2572f2b477fe^active=true",function(name){
console.log(name.data.operation);
console.log(name);
});
*/
var c = this;
// Use a position indicator to know which record to update
c.notePos = 0;
//spUtil.addInfoMessage("Welcome");
//-----------------------------------------------------------------------------
// CREATE | create prepopulate with default values and display it to be updated
//-----------------------------------------------------------------------------
c.newNote = function() {
c.server.get({
action: 'newNote'
}).then(function(r) {
//The unshift method is like the push method except that it shoves the item s onto the
//front of this array instead of at the end. It returns the array 's new length
c.data.notes.unshift(r.data.newNote);
c.data.noteID = r.data.noteID; //update scope
$rootScope.noteID = c.data.noteID;//update rootScope
$rootScope.myJson = {"sys_id" : c.data.noteID};
//eventName, data = {} or a simple value
$rootScope.$emit('selectNote', c.data.noteID);//send new data to other widgets
$rootScope.$broadcast('selectNote', {"sys_id" : c.data.noteID});
});
}
c.selectItem = function(idx) {//powerful tool
// Set the position indicator to the index value passed in on select
c.notePos = idx;
var id = c.data.notes[idx].sys_id;
console.log('Note ID: ' + id);
$rootScope.noteID = id; //passing data
$rootScope.myJson = {"sys_id" : id}; //passing data
$rootScope.$emit('selectNote', id);
$rootScope.$broadcast('selectNote', {"sys_id" : id});
}
//-----------------------------------------------------------
// RECORD UPDATED BY OTHER WIDGET
//-----------------------------------------------------------
// Subscribe to event. Set the new title and note values on the
// c.data object
$rootScope.$on('updateTitle', function(event,data) {
c.data.notes[c.notePos].title = data.title;
c.data.notes[c.notePos].note = data.note;
});
//--------------------------------------------------------
// RECORD DELETED IN THE BODY WIDGET
//--------------------------------------------------------
$rootScope.$on('deleteNote', function(event,data) {
c.data.notes.splice($scope.notePos, 1);
});
// Record removed from data object on the client and passed to server
c.snNoteUpdate = function(name,sysID){
for (var i=0;i<c.data.notes.length;i++){
if(c.data.notes[i].sys_id == name.data.sys_id){
if(name.data.record.note){
c.data.notes[i].note = name.data.record.note.display_value;
}
if(name.data.record.title){
c.data.notes[i].title = name.data.record.title.display_value;
}
c.server.update();
}
}
}
// Record removed from data object on the server and passed back to client
c.snNoteDelete = function(sysID){
c.server.get({
action: 'snDeleteNote',
noteID: sysID
}).then(function(r){
c.data.notes = r.data.notes;
});
}
//-------------------------------------------------------------------
// Use Record Watch
//-------------------------------------------------------------------
spUtil.recordWatch($scope, "x_snc_createnotes_note", "numberANYTHING", function(name) {
console.log("OPERATION : "+name.data.operation);
console.log("NAME : "+name);
// Respond to the Record Insert
// Fast and easy... replace the client data object with the server data object
if(name.data.operation == "insert"){
c.server.refresh();
}
// Respond to Record Update and Delete - Client Script
// Calls a Client Script function to do the update and pass the updated data object
// to the server.
if(name.data.operation == "update"){
c.snNoteUpdate(name, name.data.sys_id);
}
// Calls a Client Script function which does the update on the server and passes
// the updated data object back to the client.
if(name.data.operation == "delete"){
c.snNoteDelete(name.data.sys_id);
}
});
}
//=======================================================================================================================
//
//
(function(input,data,$sp,gs,options) {
/* populate the 'data' object */
/* e.g., data.table = $sp.getValue('table'); */
/*
Server-side API
The server-side Widget API class is:
GlideSPScriptable: Methods for use in Service Portal widget Server Scripts. Access the GlideSPScriptable methods using the global $sp object. For example, $sp.canRead().
canReadRecord(): returns true if the user can read the specified GlideRecord
getCatalogItem(): returns a model and view model for a sc_cat_item or sc_cat_item_guide
getDisplayValue: returns the display value of the specified field from either the widget's sp_instance or sp_portal record
getField(): returns information about the specified field in a GlideRecord
getFields(): checks the specified list of field names, and returns an array of valid field names
getFieldsObject(): checks the specified list of field names and returns an object of valid field names
getForm(): returns the form
getListColumns(): returns a list of the specified table's columns in the specified view
getMenuHREF(): returns the (?id=) portion of the URL based on the sp_menu type
getMenuItems(): returns an array of menu items for the specified instance
getParameter(): returns the value of the specified parameter
getPortalRecord(): returns the portal's GlideRecord
getRecord(): returns the current portal context
getRecordDisplayValues(): copies display values for the specified fields into the data parameter
getRecordElements(): for the specified fields, copies the element's name, display value, and value into the data parameter
getRecordValues(): copies values for the specified field names from the GlideRecord into the data parameter
getStream(): gets the activity stream for the specified record. This method works on tables which extend the Task table
getUserInitials(): returns the user's initials
getValue(): returns the value of the specified parameter
getValues(): copies values from the request or instance to the data parameter
getWidget(): gets a widget by id or sys_id, executes that widget's server script using the provided options, then returns the widget model
For the complete API documentation, including method arguments and return values, follow the links to the API classes.
Server-side Debugging
The server-side GlideSystem class includes methods which can be used for logging/debugging:
gs.log() - Global API
gs.logError() - Global API
gs.logWarning() - Global API
gs.warn() - Scoped API
gs.info() - Scoped API
gs.debug() - Scoped API
gs.error() - Scoped API
gs.addInfoMessage() - Scoped API and Global API
gs.addErrorMessage() - Scoped API and Global API
Widget Option Schema
Using widgets options makes widgets more easily reusable. The widget option schema defines
the user-configurable fields. To add, edit, or delete option fields, select the Edit
Options Schema menu item in the Widget Editor menu.
*/
//create an array to populate without notes
data.notes = [];
var noteGR = new GlideRecord('x_snc_createnotes_note');
noteGR.addQuery('user', gs.getUser().getID());
noteGR.orderByDesc('sys_created_on');
noteGR.setLimit(options.maximum_records_to_display);
noteGR.query();
while (noteGR.next()) {
var noteObj = {};
//use service portal helper method to get some display values
$sp.getRecordDisplayValues(noteObj, noteGR, 'number,title,sys_id');
//get the first 20 characters of the description
noteObj.note = noteGR.getValue('note');//.slice(0,20);
//push the populated obj into the array
data.notes.push(noteObj);
}
if (input) {
if (input.action == 'newNote') {
var newNote = new GlideRecord('x_snc_createnotes_note');
newNote.newRecord();
var id = newNote.insert();
data.noteID = id;
data.newNote = {};
//emptyJson , gr ,fields-needed
$sp.getRecordValues(data.newNote,newNote,"title,note,sys_id");
}
if (input.action == 'snDeleteNote') {
var delNote = new GlideRecord('x_snc_createnotes_note');
// The notes record should already be gone. Just
// making sure it no longer exists.
if(delNote.get(input.noteID)){
delNote.deleteRecord();
}
}
}
})(input,data,$sp,gs,options);
//=================================================================================================================================
//
//
[{"hint":"Specify a title for the Notes List widget","name":"title","section":"other","default_value":"NOTES NAV BAR","label":"Title","type":"string"},{"hint":"Select the maximum number of records to display","name":"maximum_records_to_display","section":"other","default_value":"5","label":"Maximum records to display","type":"choice","choices":[{"label":"2","value":"2"},{"label":"3","value":"3"},{"label":"5","value":"5"},{"label":"7","value":"7"},{"label":"11","value":"11"},{"label":"13","value":"13"},{"label":"17","value":"17"}]}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment