Slush bucket widget - save button

walshy
Giga Expert

I am using the slush bucket widget on a portal page so I can use a m2m table to link multiple songs to a gig. I have the songs in in the 'available' bucket and the widget works for me, but I am struggling to work out how to make the 'save' work like it would in the CMS through the edit option. 

I am trying to decide if I should create a save button on the widget or if I should have the save button on the record form do the save once the songs are added to the gig. 

find_real_file.png

If I do the slush widget (which I have been attempting to do now) I have attempted to take some of the code from the record widget save button but I am struggling with that. Which is what made me think about using that button to save the details in the slush widget. 

Any suggestions on the best way to tackle this? 

I looked at the list collector option as a variable on the form, but I couldn't work out how to make the songs save in the related list as I needed. 

Below is the widget code I have so far

html

<div>
	<h4>Select songs for this gig</h4>
  <button type="button" class="btn btn-primary action-btn">Save songs</button>
  <button ng-if="getPrimaryAction()" type="submit" ng-click="triggerUIAction(getPrimaryAction())" ng-disabled="submitting" class="btn btn-primary action-btn pull-right ng-scope" gsft_id="{{::action.sys_id}}">Save selections<!-- ngIf: saveButtonSuffix --><span ng-if="saveButtonSuffix" class="ng-binding ng-scope">(Ctrl + s)</span><!-- end ngIf: saveButtonSuffix --></button>
    
  <div class="row">

    <div class="col-sm-6">
      <div class="panel panel-default">
        <div class="panel-heading">
          <h4 class="panel-title">${Select from below}</h4>
        </div>
        <div class="available list-group slush-scrollable" 
             as-sortable="c.availableAs" 
             ng-model="c.data.all">
          <div ng-repeat="item in c.data.all | filter:c.search" 
               as-sortable-item 
               ng-dblclick="c.onDblClick(item)"
               ng-class="{used: item.used}"
               class="list-group-item">
            <div as-sortable-item-handle>
              <span>{{item.u_song_title.display_value}}</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="col-sm-6">
      <div class="panel panel-default">
        <div class="panel-heading">
          <h4 class="panel-title">${In gig}</h4>
        </div>
        <div class="list-group slush-scrollable" as-sortable="c.selectedAs" ng-model="c.selected">
          <div ng-repeat="item in c.selected" 
               as-sortable-item
               ng-dblclick="c.onSelDblClick(item)"
               class="list-group-item">
            <div as-sortable-item-handle>
              <span>{{item.u_song_title.display_value}}</span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>  
  <div>
  </div>
</div>

CSS

.as-sortable-placeholder {
  background-color: #eee;
}

.slush-scrollable {
  height: 240px;
  overflow-y: scroll;
  overflow-x:hidden;
}

.panel  > .list-group:last-child .list-group-item:last-child {
	border-bottom-width: 1px;
  border-bottom-style: solid;
  border-radius: 0;
}

.used {
	max-height: 0;
  overflow: hidden;
  padding: 0;
  border: none;
}

.available > .list-group-item {
	transition: all 1s;
}

.btn-form-menu {
	vertical-align: inherit;
  padding: inherit;
  background: none;
}

Client

function($rootScope, $scope) {
	var c = this;
	c.selected = [];

	// ng-sortable clone means cannot reorder
	c.availableAs = {
		itemMoved: function (event) {
			event.source.itemScope.item.used = true;
		},
		clone: true // clone this side
	}

	c.selectedAs = {
		itemMoved: function (event) {
			// moved back to available
			var item = event.source.itemScope.item;
			moveToAvailable(item);
			removeItem(c.data.all, item);
		},
		dragStart: function () {
			c.availableAs.clone = false;
		},
		dragEnd: function () {
			c.availableAs.clone = true;
		}
	}

	// double moves from Available to Selected
	c.onDblClick = function(item) {
		var t = angular.copy(item);
		item.used = true; // original is now used
		c.selected.push(t);
	}

	// double on selected removes and unsets Available used
	c.onSelDblClick = function(item) {
		moveToAvailable(item);
		removeItem(c.selected, item);
	}

	function removeItem(array, item) {
		var n = array.indexOf(item);
		if (n !== -1)
			array.splice(n, 1);		
	}
	
	function moveToAvailable(item) {
		var t = item.sys_id.value;
		angular.forEach(c.data.all, function(target) {
			if (target.sys_id.value == t)
				target.used = false;
		})		
	}
	
	function _save() {
		var primaryAction = $scope.getPrimaryAction();
    if (primaryAction)
      $scope.triggerUIAction(primaryAction);
	}
	
	$scope.triggerUIAction = function(action) {
		if ($scope.data.disableUIActions && !action.primary) {
      return;
    }
}

}

server

(function () {
	// grab the filtered songs
	data.all = [];
	var filterQuery = "u_perform_statusIN1,2,3^u_song_status=2";
	var gr = new GlideRecord('x_120100_band_songs');
				
	gr.orderBy('u_song_title');
  
	gr.addEncodedQuery(filterQuery);
	gr.query();
  while (gr.next()) {
    var t = $sp.getRecordElements(gr, 'u_song_title,sys_id');
		data.all.push(t);
	}
})();

 

1 ACCEPTED SOLUTION

Hi Walshy,

In your server script for the input:
     addSong.songs = input.songs[indx]
should be 
     addSong.songs = input.songs[indx].sys_id.value
according to your screenshot of the Object and if the "songs" field is a reference field on the m2m table.

Also as a side note to clear things up a little in your comments of your Client Script in the server.get() method. (Hopefully you don't mind)
find_real_file.png

 

 

 

View solution in original post

11 REPLIES 11

ChrisBurks
Mega Sage

For future reference, if you wanted to just use the "Save" button from the record form you can do something like below in the client script of the slush bucket widget.

If I'm not mistaken it should be possible to use this snippet to listen for the submission of the record:

$rootScope.$on('sp.form.submitted', function(evt, data){
	
})

Then from that kick off the c.saveMySongs() code to save the slush bucket stuff. Together would look like this:

$rootScope.$on('sp.form.submitted', function(evt, data){
		c.saveMySongs()
		
})

Summary:
That snippet just listens for when the form is submitted and when it is also perform the code code within the listener.

rahulpandey
Kilo Sage

Hi,

I believe you want to have a list collector element instead on glidelist element, which servicenow renders when there is a list collector on a catalog item.

I have tried this and working fine, I have tried below approach.

- hide the actual variable via a client script (UI type of script would be service portal)// so this will hide actual variable on portal.

- Create new variable on catalog item/ record produce as type : UI macro and choose your widget.

so now, on portal, your widget would display and on native view normal list collector would be visible

Next step, in you client controller, you would be able to use g_form api like below

$scope.page.g_form();

Whenever someone is adding some value from left to right, just keep setting the value to hidden variable like below

$scope.page.g_form().setValue('your hidden variable', 'you you moved from left to right');

I hope this would help.