Group notification messages by category and turn on/off through service portal widget

mballinger
Mega Guru

Hello,

I have a service portal widget that I am needing assistance on. The widget code can be found on my previous posting How to set/pass values from checkbox field in portal . Essentially what it does is allow users to turn on/off notifications from within a widget. The notifications right now are being pulled from the cmn_notif_message table. I am now finding that messages only register on the table if a user has been a recipient of the message or if a user has turned a notification on/off. 

What I need to add to the widget. I will more than likely need to reference the sysevent_email_action table to ensure all notifications are being pulled back. The next thing I will need to do is automatically default the values to true. Once the record has been turned on/off, a new record should be created on the cmn_notif_message table. Next, I will need to display the category for the notification, and under the category, I will need to display the notifications. The category should be a collapsible field that has a toggle. The toggle at the category level, if turned on/off, should turn on/off all notifications within its given category. The same thing needs to apply to records being created on the cmn_notif_message table as this table holds subscribed/unsubscribed notifications.

The widget works as expected with the notifications turning on/off. The new additions is what is missing from the code. Again the new additions is bringing in category level info as well as referencing the sysevent_email_action table and defaulting everything to true until a selection is made.

I will paste the code here for reference as well:

HTML:

<div class="panel panel-default">
	<table class="table">
	  <thead>
		<tr>
		  <th scope="col">Notification Name</th>
		  <th scope="col">Device</th>
		  <th scope="col">Toggle On/Off</th>
		</tr>
	  </thead>
	  <tbody>
		<tr ng-repeat="obj in c.data.list">
		  <td>{{obj.message}}</td>
		  <td>{{obj.name}}</td>
		  <td><input id="checkbox" type="checkbox" ng-model="toggle" ng-checked="obj.toggle" ng-click="c.update(obj.sys_id)"></td>
		</tr>
	  </tbody>
	</table>
</div>

Client Script:

api.controller=function() {

  var c = this;
	
	c.update = function(sys_id) {
		input = {};
		input.sys_id = sys_id;
		input.action = 'UpdateRec';
		
		c.server.get(input).then(function(r) {
            c.data = r.data;
        });
	};
	
};

Server Script:

(function() {
    var currentUser = gs.getUserID();
    data.list = [];

	//sys_id for the value unsubscribe, at least in my PDI
    var unsubscribe = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id for unsubscribe

    if (input && input.action == 'UpdateRec') {
		//If we are passing in input, we toggle the record
        var updateRec = new GlideRecord('cmn_notif_message');
        updateRec.get(input.sys_id);
        if (updateRec.notification_filter == unsubscribe) {
			//if the box was unchecked, we clear the value
            updateRec.notification_filter = '';
        } else {
			//if the box was checked, we add the value
            updateRec.notification_filter = unsubscribe;
        }
		//update the record
        updateRec.update();
    }

    var gr = new GlideRecord('cmn_notif_message');
    gr.addQuery('user', currentUser);
    gr.query();
    while (gr.next()) {
        var notifObj = {};

        notifObj.message = gr.getDisplayValue('notification');
        notifObj.name = gr.getDisplayValue('user');
		//Here we add the sys_id of the record and the current state for the checkbox
        notifObj.sys_id = gr.getUniqueValue();
        notifObj.toggle = false;

        if (gr.notification_filter == unsubscribe) {
            notifObj.toggle = true;
        }

        data.list.push(notifObj);
    }

})();

Thanks!

@Michael Jones - GlideFast 

1 ACCEPTED SOLUTION

Michael Jones -
Giga Sage

@mballinger  Ok, this is...pretty much functional!

It gets all of the notifications, groups them by category, displays them in a collapsable list. It also check whether they have already unsubscribed to each specific notification and sets the individual checkboxes based on the results. If they have not specifically unsubscribed, they show as subscribed. Each category has a slide to disable all, enable all - here we have a small dilemma, so if any notifications in the category are unsubscribed, the slider will be on the "disable all" side so that if they slide it to "enable all", the unsubscribed notifications will be checked. Finally we do not make updates with each click (that could lead to nightmare to manage) so we have an Update button at the top - when clicked it will process the updates - for each notification that was changed it will check to see if a cmn_notif_message record exists and if so, update it. If no record exists, it only creates a record if the change was to unsubscribe, since subscribed is the default with no record. 

Seems to work like a charm! 

HTML: 

<div class="panel panel-default list">
  <div class="header">
    <h2 class="heading">${Notification Preferences}</h2>
    <input type="submit" class="btn btn-primary post-btn ng-scope update" value="Update" aria-label="Post" ng-disabled="data.isPosting" role="button" ng-click="c.update()">
  </div>
  <div class="category" ng-repeat="category in c.data.categories">
    <div class="accordian-div">
      <uib-accordion>
        <div uib-accordion-group  class="panel-default" is-open="status.open">
          <uib-accordion-heading>
            {{category.name}}
            <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i>
          </uib-accordion-heading>
          <div class="slider">
            <input class="checkbox" id="{{category.sys_id}}" type="checkbox" ng-model="category.enabled" />
            <label for="checkbox1" class="checkbox-label"  ng-click="c.setUserPreference(category.sys_id)">
              <span ng-class="{active : data.showCategories == false, inactive : data.showCategories == true}"
                    class="off">Disable All</span>
              <span ng-class="{active : data.showCategories == true, inactive : data.showCategories == false}"
                    class="on">Enable All</span>
            </label>
          </div>
          <table class="table">
            <thead>
              <tr>
                <th scope="col">Notification Name</th>
                <th scope="col">Toggle On/Off</th>
              </tr>
            </thead>
            <tbody>
              <tr ng-repeat="notif in category.notifications">
                <td>{{notif.name}}</td>
                <td><input id="checkbox" type="checkbox" ng-model="notif.cmn_notif.subscribed" ng-checked="notif.cmn_notif.subscribed" ng-click="c.toggle(notif)"></td>
              </tr>
            </tbody>
          </table>
        </div>
      </uib-accordion>
    </div>
  </div>
</div>

CSS:

.update {
  margin: 5px;
}

.heading {
  margin-left: 10px;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}

.panel-group {
margin-bottom: 0px !important;
}

.slider {
  right: -315px;
}

.list {
  display:block;
}

.checkbox-label {
  transition: all .25s ease-in-out;
  display:block;
  background:#ccc;
  height:25px;
  width:50px;
  border-radius:50px;
  margin:23px 100px;
  position:relative;
  font-weight: 500;
  box-shadow:0 0 0 2px #ccc;
  .on {
    display:block;
    position:absolute;
    z-index:0;
    left:60px;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .off {
    display:block;
    position:absolute;
    z-index:0;
    right:60px;
    text-align:right;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .active {
    color: green;
  }
  .inactive {
    color: gray;
  }
  &:before {
    content:'';
    display:block;
    position:absolute;
    z-index:1;
    top:0;
    right:30px;
    border-radius:50px;
    height:25px;
    width:25px;
    background:white;
    box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px #ccc;
  }
}
.checkbox {
  position:absolute;
  left:-5000px;
  &:checked {
    + .checkbox-label {
      background: green;
      box-shadow:0 0 0 2px green;
      &:before {
        left:30px;
        box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px green;
      }
    }
  }
}


.category {
  display:block;
}

Server:

(function() {
    var currentUser = gs.getUserID();
    data.updates = [];
    data.notifications = [];
    data.categories = [];
    data.list = [];

    var unsubscribe = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id for unsubscribe

    if (input && input.action == 'UpdateRec') {
        //Based on the input we process updates
        input.data.updates.forEach(checkForUpdate);
        input.data.updates = [];
    } 
        //First we get all of the possible notfications that can be sent.
        var sysevent_email_action = new GlideRecord('sysevent_email_action');
        sysevent_email_action.addActiveQuery();
        sysevent_email_action.orderBy('category');
        sysevent_email_action.query();
        while (sysevent_email_action.next()) {
            //Create an object to hold our notification details
            var notifObj = {};
            notifObj.name = sysevent_email_action.getValue('name');
            notifObj.sys_id = sysevent_email_action.getUniqueValue();
            notifObj.category_name = sysevent_email_action.getDisplayValue('category');
            notifObj.category_id = sysevent_email_action.getValue('category');
            notifObj.cmn_notif = checkForNotif(notifObj.sys_id);
            //For now we push this to a seperate array, every time. 
            data.list.push(notifObj);
            //Now we need to determine if we have added this category to our array already
            if (JSON.stringify(data.categories).indexOf(notifObj.category_id) == -1) {
                //If not then we create an object for the category
                var category = {};
                category.name = notifObj.category_name;
                category.sys_id = notifObj.category_id;
                category.enabled = true;
                category.notifications = [];
                //Add the notification object to the notifications array
                category.notifications.push(notifObj);
                //Add the category object to the categories array
                data.categories.push(category);
            } else {
                //If the Category is already in our array, we find the object for that category and 
                //push the notification to the notifications array
                data.categories.forEach(checkCategory);
            }
			
			if(notifObj.cmn_notif.subscribed == false) {
				category.enabled = false;
			}
        
    }

    function checkForNotif(notification) {
		//We build an object to hold info on the cmn_notif_message results
        var cmn_notif = {};
        cmn_notif.updated = false;
        cmn_notif.sys_id = false;
        cmn_notif.subscribed = true;
		
		//Check to see if a record already exists for the current notification
        var notif = new GlideRecord('cmn_notif_message');
        notif.addQuery('user', currentUser);
        notif.addQuery('notification', notification);
        notif.query();

        if (notif.next()) {
			//if it exists we get the ID for later
            cmn_notif.sys_id = notif.getUniqueValue();
            if (notif.notification_filter == unsubscribe) {
				//we check to see if they have already unsubscribed
                cmn_notif.subscribed = false;
            }
        }
        //We need to know where we started for when we update.
        cmn_notif.starting_toggle = cmn_notif.subscribed;
        return cmn_notif;
    }

    function checkCategory(category) {
        //We only wan to add notifications to the correct category
        if (category.sys_id == notifObj.category_id) {
            category.notifications.push(notifObj);
        }
    }

    function checkForUpdate(notification) {
        //We only need to process an update if the value is different than the original value
        if (notification.cmn_notif.subscribed != notification.cmn_notif.starting_toggle) {
            //The value changed, so we need to take some action: 
            var cmn_notif = new GlideRecord('cmn_notif_message');
            //check to see if there is already a cmn_notif_message record;
            if (notification.cmn_notif.sys_id) {
                //a cmn_notif_message record already exists, so we set the value for advanced_filter
                cmn_notif.get(notification.cmn_notif.sys_id);
                if (notification.cmn_notif.subscribed) {
                    cmn_notif.notification_filter = '';
                } else {
                    cmn_notif.notification_filter = unsubscribe;
                }
                cmn_notif.update();
				//Since we are passing back to the client-side we need to reset the starting toggle
				//Otherwise additional changes in the same session will not be processed. 
				notification.cmn_notif.starting_toggle = notification.cmn_notif.subscribed;
            } else {
                //The value changed, but no cmn_notif_message record exists yet
                //we only need to create a record if they want to unsubscribe, since subscribed is the default
                if (notification.cmn_notif.subscribed == false) {
                    cmn_notif.initialize();
                    cmn_notif.notification = notification.sys_id;
                    cmn_notif.user = currentUser;
                    cmn_notif.notification_filter = unsubscribe;
					cmn_notif.insert();

                }
				//Since we are passing back to the client-side we need to reset the starting toggle
				//Otherwise additional changes in the same session will not be processed. 
				notification.cmn_notif.starting_toggle = notification.cmn_notif.subscribed;
            }

        }
    }

})();

Client: 

api.controller = function() {
    /* widget controller */
    var c = this;
	
		c.toggle = function(notification) {
		if(JSON.stringify(c.data.updates).indexOf(notification.sys_id) == -1) {
		c.data.updates.push(notification);
		} 
	};

    c.update = function() {
        input = {};
        input.data = c.data;
        input.action = 'UpdateRec';

        c.server.get(input).then(function(r) {
            c.data = r.data;
 
        });
    };

    c.setUserPreference = function(category) {

        c.data.categories.forEach(function(item) {
            if (item.sys_id == category) {
                if (item.enabled == true) {
                    item.enabled = false;
                    item.notifications.forEach(function(notif) {
                        notif.cmn_notif.subscribed = false;
						c.toggle(notif);
                    });
                } else {
                    item.enabled = true;
                    item.notifications.forEach(function(notif) {
                        notif.cmn_notif.subscribed = true;
						c.toggle(notif);
                    });
                }
            }
        });

    };
	



};

find_real_file.png

I hope this helps!

If this was helpful, or correct, please be kind and mark the answer appropriately.

Michael Jones - Proud member of the GlideFast Consulting Team!

I hope this helps!
Michael D. Jones
Proud member of the GlideFast Consulting Team!

View solution in original post

5 REPLIES 5

Tom Sienkiewicz
Mega Sage

Hi, a little busy RN so perhaps I will give this a proper look later on, but just 2 quick thoughts:

1. instead of hardcoding this sys_id for unsubscribe, consider creating a system property for it.

2. When you collect all the notifications, make sure to only grab those with "subscribable" set to true.

I also think that perhaps it is not necessary for the user to see all the notifications up front. Why would they be concerned with setting a preference for  a notification they never got yet? 🙂 I think that typically, the user gets a notification and then they decide if it is valuable for them or not.

It seems you're intending to recreate the user preferences for notifications on SP, perhaps review how these work on the backend and also inspect the HTMLetc. for them as a sort of guidance. 

Michael Jones -
Giga Sage

@mballinger 

Here is a bit of progress - nowhere near finished, but a rough-draft of the data representation I "think" you are going for. Not very refined, but somewhat functional client-side (does no updates server side).

HTML: 

<div class="panel panel-default">
  <div class="category" ng-repeat="obj in c.data.categories">
<uib-accordion>
<div uib-accordion-group  class="panel-default" is-open="status.open">
      <uib-accordion-heading>
        {{obj.name}}
        <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i>
      </uib-accordion-heading>

	<table class="table">
	  <thead>
		<tr>
		  <th scope="col">Notification Name</th>
		  <th scope="col">Toggle On/Off</th>
		</tr>
	  </thead>
	  <tbody>
		<tr ng-repeat="notif in obj.notifications">
		  <td>{{notif.name}}</td>
		  <td><input id="checkbox" type="checkbox" ng-model="toggle" ng-checked="obj.enabled" ng-click="c.update(obj.sys_id)"></td>
		</tr>
	  </tbody>
	</table>
    </div>
    </uib-accordion>
            <input class="checkbox" id="{{obj.sys_id}}" type="checkbox" ng-model="obj.enabled"
         ng-click="c.setUserPreference('{{obj.sys_id}}')" />
  <label for="checkbox1" class="checkbox-label"  ng-click="c.setUserPreference(obj.sys_id)">
    <span ng-class="{active : data.showCategories == false, inactive : data.showCategories == true}"
          class="off">Disable</span>
    <span ng-class="{active : data.showCategories == true, inactive : data.showCategories == false}"
          class="on">Enable</span>
  </label>
  </div>
</div>

CSS: 

.checkbox-label {
  transition: all .25s ease-in-out;
  display:block;
  background:#ccc;
  height:25px;
  width:50px;
  border-radius:50px;
  margin:23px 100px;
  position:relative;
  font-weight: 500;
  box-shadow:0 0 0 2px #ccc;
  .on {
    display:block;
    position:absolute;
    z-index:0;
    left:60px;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .off {
    display:block;
    position:absolute;
    z-index:0;
    right:60px;
    text-align:right;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .active {
    color: $FIS-green;
  }
  .inactive {
    color: gray;
  }
  &:before {
    content:'';
    display:block;
    position:absolute;
    z-index:1;
    top:0;
    right:30px;
    border-radius:50px;
    height:25px;
    width:25px;
    background:white;
    box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px #ccc;
  }
}

.checkbox {
  position:absolute;
  left:-5000px;
  &:checked {
    + .checkbox-label {
      background:$FIS-green;
      box-shadow:0 0 0 2px $FIS-green;
      &:before {
        left:30px;
        box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px $FIS-green;
      }
    }
  }
}

.category {
  display:block;
}

Server:

(function() {
    var currentUser = gs.getUserID();
    data.notifications = [];
	data.categories = [];

    var unsubscribe = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id for unsubscribe

/*     to do later
    if (input && input.action == 'UpdateRec') {
 
        var updateRec = new GlideRecord('cmn_notif_message');
        updateRec.get(input.sys_id);
        if (updateRec.notification_filter == unsubscribe) {
            updateRec.notification_filter = '';
        } else {
            updateRec.notification_filter = unsubscribe;
        }
        updateRec.update();
    }
*/

    var sysevent_email_action = new GlideRecord('sysevent_email_action');
    sysevent_email_action.addActiveQuery();
    sysevent_email_action.query();
    while (sysevent_email_action.next()) {
        var notifObj = {};

        notifObj.name = sysevent_email_action.getValue('name'); 
		notifObj.sys_id = sysevent_email_action.getUniqueValue();
        notifObj.category_name = sysevent_email_action.getDisplayValue('category');
        notifObj.category_id = sysevent_email_action.getValue('category');
        notifObj.toggle = false;

        data.list.push(notifObj);
		if(JSON.stringify(data.categories).indexOf(notifObj.category_id) == -1) {
			var category = {};
			category.name = notifObj.category_name;
			category.sys_id = notifObj.category_id;
			category.enabled = true;
			category.notifications = [];
			category.notifications.push(notifObj);
			data.categories.push(category);
		} else {
			data.categories.forEach(checkCategory);
		}
    }
	
	function checkCategory(category) {
		
		if(category.sys_id == notifObj.category_id) {
					category.notifications.push(notifObj);
				}
	}

})();

Client:

api.controller=function() {
  /* widget controller */
  var c = this;
	
	c.update = function(sys_id) {
		input = {};
		input.sys_id = sys_id;
		input.action = 'UpdateRec';
		
		c.server.get(input).then(function(r) {
            c.data = r.data;
			      //c.options = r.options
        });
	}
	
	c.setUserPreference = function(category) {
		console.log('clicked')
		console.log(category);
		c.data.categories.forEach(function(item) {
			if(item.sys_id == category) {
				if(item.enabled == true) {
				item.enabled = false;
				} else {
					item.enabled = true;
				}
			}
		});
		
	}
	
};

I'll keep tweaking in my spare time. 

I hope this helps!

If this was helpful, or correct, please be kind and mark the answer appropriately.

Michael Jones - Proud member of the GlideFast Consulting Team!

I hope this helps!
Michael D. Jones
Proud member of the GlideFast Consulting Team!

Michael Jones -
Giga Sage

@mballinger  Ok, this is...pretty much functional!

It gets all of the notifications, groups them by category, displays them in a collapsable list. It also check whether they have already unsubscribed to each specific notification and sets the individual checkboxes based on the results. If they have not specifically unsubscribed, they show as subscribed. Each category has a slide to disable all, enable all - here we have a small dilemma, so if any notifications in the category are unsubscribed, the slider will be on the "disable all" side so that if they slide it to "enable all", the unsubscribed notifications will be checked. Finally we do not make updates with each click (that could lead to nightmare to manage) so we have an Update button at the top - when clicked it will process the updates - for each notification that was changed it will check to see if a cmn_notif_message record exists and if so, update it. If no record exists, it only creates a record if the change was to unsubscribe, since subscribed is the default with no record. 

Seems to work like a charm! 

HTML: 

<div class="panel panel-default list">
  <div class="header">
    <h2 class="heading">${Notification Preferences}</h2>
    <input type="submit" class="btn btn-primary post-btn ng-scope update" value="Update" aria-label="Post" ng-disabled="data.isPosting" role="button" ng-click="c.update()">
  </div>
  <div class="category" ng-repeat="category in c.data.categories">
    <div class="accordian-div">
      <uib-accordion>
        <div uib-accordion-group  class="panel-default" is-open="status.open">
          <uib-accordion-heading>
            {{category.name}}
            <i class="pull-right glyphicon" ng-class="{'glyphicon-chevron-down': status.open, 'glyphicon-chevron-right': !status.open}"></i>
          </uib-accordion-heading>
          <div class="slider">
            <input class="checkbox" id="{{category.sys_id}}" type="checkbox" ng-model="category.enabled" />
            <label for="checkbox1" class="checkbox-label"  ng-click="c.setUserPreference(category.sys_id)">
              <span ng-class="{active : data.showCategories == false, inactive : data.showCategories == true}"
                    class="off">Disable All</span>
              <span ng-class="{active : data.showCategories == true, inactive : data.showCategories == false}"
                    class="on">Enable All</span>
            </label>
          </div>
          <table class="table">
            <thead>
              <tr>
                <th scope="col">Notification Name</th>
                <th scope="col">Toggle On/Off</th>
              </tr>
            </thead>
            <tbody>
              <tr ng-repeat="notif in category.notifications">
                <td>{{notif.name}}</td>
                <td><input id="checkbox" type="checkbox" ng-model="notif.cmn_notif.subscribed" ng-checked="notif.cmn_notif.subscribed" ng-click="c.toggle(notif)"></td>
              </tr>
            </tbody>
          </table>
        </div>
      </uib-accordion>
    </div>
  </div>
</div>

CSS:

.update {
  margin: 5px;
}

.heading {
  margin-left: 10px;
}

.header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
}

.panel-group {
margin-bottom: 0px !important;
}

.slider {
  right: -315px;
}

.list {
  display:block;
}

.checkbox-label {
  transition: all .25s ease-in-out;
  display:block;
  background:#ccc;
  height:25px;
  width:50px;
  border-radius:50px;
  margin:23px 100px;
  position:relative;
  font-weight: 500;
  box-shadow:0 0 0 2px #ccc;
  .on {
    display:block;
    position:absolute;
    z-index:0;
    left:60px;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .off {
    display:block;
    position:absolute;
    z-index:0;
    right:60px;
    text-align:right;
    opacity:1;
    min-width:300px;
    line-height:25px;
  }
  .active {
    color: green;
  }
  .inactive {
    color: gray;
  }
  &:before {
    content:'';
    display:block;
    position:absolute;
    z-index:1;
    top:0;
    right:30px;
    border-radius:50px;
    height:25px;
    width:25px;
    background:white;
    box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px #ccc;
  }
}
.checkbox {
  position:absolute;
  left:-5000px;
  &:checked {
    + .checkbox-label {
      background: green;
      box-shadow:0 0 0 2px green;
      &:before {
        left:30px;
        box-shadow:0 3px 3px rgba(0,0,0,.2),0 0 0 2px green;
      }
    }
  }
}


.category {
  display:block;
}

Server:

(function() {
    var currentUser = gs.getUserID();
    data.updates = [];
    data.notifications = [];
    data.categories = [];
    data.list = [];

    var unsubscribe = 'c1bfa4040a0a0b8b001eeb0f3f5ee961'; //sys_id for unsubscribe

    if (input && input.action == 'UpdateRec') {
        //Based on the input we process updates
        input.data.updates.forEach(checkForUpdate);
        input.data.updates = [];
    } 
        //First we get all of the possible notfications that can be sent.
        var sysevent_email_action = new GlideRecord('sysevent_email_action');
        sysevent_email_action.addActiveQuery();
        sysevent_email_action.orderBy('category');
        sysevent_email_action.query();
        while (sysevent_email_action.next()) {
            //Create an object to hold our notification details
            var notifObj = {};
            notifObj.name = sysevent_email_action.getValue('name');
            notifObj.sys_id = sysevent_email_action.getUniqueValue();
            notifObj.category_name = sysevent_email_action.getDisplayValue('category');
            notifObj.category_id = sysevent_email_action.getValue('category');
            notifObj.cmn_notif = checkForNotif(notifObj.sys_id);
            //For now we push this to a seperate array, every time. 
            data.list.push(notifObj);
            //Now we need to determine if we have added this category to our array already
            if (JSON.stringify(data.categories).indexOf(notifObj.category_id) == -1) {
                //If not then we create an object for the category
                var category = {};
                category.name = notifObj.category_name;
                category.sys_id = notifObj.category_id;
                category.enabled = true;
                category.notifications = [];
                //Add the notification object to the notifications array
                category.notifications.push(notifObj);
                //Add the category object to the categories array
                data.categories.push(category);
            } else {
                //If the Category is already in our array, we find the object for that category and 
                //push the notification to the notifications array
                data.categories.forEach(checkCategory);
            }
			
			if(notifObj.cmn_notif.subscribed == false) {
				category.enabled = false;
			}
        
    }

    function checkForNotif(notification) {
		//We build an object to hold info on the cmn_notif_message results
        var cmn_notif = {};
        cmn_notif.updated = false;
        cmn_notif.sys_id = false;
        cmn_notif.subscribed = true;
		
		//Check to see if a record already exists for the current notification
        var notif = new GlideRecord('cmn_notif_message');
        notif.addQuery('user', currentUser);
        notif.addQuery('notification', notification);
        notif.query();

        if (notif.next()) {
			//if it exists we get the ID for later
            cmn_notif.sys_id = notif.getUniqueValue();
            if (notif.notification_filter == unsubscribe) {
				//we check to see if they have already unsubscribed
                cmn_notif.subscribed = false;
            }
        }
        //We need to know where we started for when we update.
        cmn_notif.starting_toggle = cmn_notif.subscribed;
        return cmn_notif;
    }

    function checkCategory(category) {
        //We only wan to add notifications to the correct category
        if (category.sys_id == notifObj.category_id) {
            category.notifications.push(notifObj);
        }
    }

    function checkForUpdate(notification) {
        //We only need to process an update if the value is different than the original value
        if (notification.cmn_notif.subscribed != notification.cmn_notif.starting_toggle) {
            //The value changed, so we need to take some action: 
            var cmn_notif = new GlideRecord('cmn_notif_message');
            //check to see if there is already a cmn_notif_message record;
            if (notification.cmn_notif.sys_id) {
                //a cmn_notif_message record already exists, so we set the value for advanced_filter
                cmn_notif.get(notification.cmn_notif.sys_id);
                if (notification.cmn_notif.subscribed) {
                    cmn_notif.notification_filter = '';
                } else {
                    cmn_notif.notification_filter = unsubscribe;
                }
                cmn_notif.update();
				//Since we are passing back to the client-side we need to reset the starting toggle
				//Otherwise additional changes in the same session will not be processed. 
				notification.cmn_notif.starting_toggle = notification.cmn_notif.subscribed;
            } else {
                //The value changed, but no cmn_notif_message record exists yet
                //we only need to create a record if they want to unsubscribe, since subscribed is the default
                if (notification.cmn_notif.subscribed == false) {
                    cmn_notif.initialize();
                    cmn_notif.notification = notification.sys_id;
                    cmn_notif.user = currentUser;
                    cmn_notif.notification_filter = unsubscribe;
					cmn_notif.insert();

                }
				//Since we are passing back to the client-side we need to reset the starting toggle
				//Otherwise additional changes in the same session will not be processed. 
				notification.cmn_notif.starting_toggle = notification.cmn_notif.subscribed;
            }

        }
    }

})();

Client: 

api.controller = function() {
    /* widget controller */
    var c = this;
	
		c.toggle = function(notification) {
		if(JSON.stringify(c.data.updates).indexOf(notification.sys_id) == -1) {
		c.data.updates.push(notification);
		} 
	};

    c.update = function() {
        input = {};
        input.data = c.data;
        input.action = 'UpdateRec';

        c.server.get(input).then(function(r) {
            c.data = r.data;
 
        });
    };

    c.setUserPreference = function(category) {

        c.data.categories.forEach(function(item) {
            if (item.sys_id == category) {
                if (item.enabled == true) {
                    item.enabled = false;
                    item.notifications.forEach(function(notif) {
                        notif.cmn_notif.subscribed = false;
						c.toggle(notif);
                    });
                } else {
                    item.enabled = true;
                    item.notifications.forEach(function(notif) {
                        notif.cmn_notif.subscribed = true;
						c.toggle(notif);
                    });
                }
            }
        });

    };
	



};

find_real_file.png

I hope this helps!

If this was helpful, or correct, please be kind and mark the answer appropriately.

Michael Jones - Proud member of the GlideFast Consulting Team!

I hope this helps!
Michael D. Jones
Proud member of the GlideFast Consulting Team!

@Michael Jones - GlideFast - This is exactly what I needed! I was able to use everything and get it to work (had to do a little tweaking). Thank you so much for putting in time and effort to help me solution this Michael!