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

Hi Malgorzata, 

I get what you have done here, but I think I have missed a step. 

I went to the console as you suggested and I get an error based around the 'get' inside the c.saveMySongs, it is telling me the get is undefined for some reason, that doesn't make sense to me. 

find_real_file.png

From the $scope console it looks like I am getting the gig sysID no worries, but the songs are not going into the c.selected array I am assuming this is because the 'get' is undefined from earlier in the client side code. 

find_real_file.png

Im attempting to understand why the 'get' in the saveMySongs is being annoying. 

Thanks


Cam.

 

it should be c.server and you have 

c.sever.get(

I missed "r" in my example 

Yeah bad typo on my behalf, I should have read through a little closer.  

That worked Malgorzata, I now just have to make sure the name of the song passes through to the m2m table. 

The m2m table fills with the gig number, but the name of the song doesn't come through, ha! the sysID and the song titles come through in the array, but when you look at the m2m table, the songs field is empty. On the m2m table this is a reference field to the x_120100_band_songs table. 

find_real_file.png

So when I look at related list table in the CMS I have no song name

find_real_file.png

But the gig and song are matching in the m2m table.

find_real_file.png

I have played around with a few different thoughts on the r.data.u_song_title in the client script thinking I needed to have the title point to the reference field somehow by doing r.data.songs.u_song_title but to no avail. 

I understand the logic of the =input.songs[indx]; as it takes the 3 fields I have pushed back via r.data from the client script. But I cant work out how to make the name of the song show up in the m2m. 

When I open the record in the m2m table it is a new blank record, so do I need to run a query on the x_120100_band_songs table to search for the song rather than add.Song.insert()? 

client

	c.saveMySongs = function(){
		//pass the data to server in order to save
    c.server.get(
			{
      action:'saveSongs',
      songs: c.selected
			}
		)
			.then(function(r){
     //pass the required song data back to server
			  c.data.sys_id = r.data.sys_id;
        c.data.number = r.data.number;
			  c.data.u_song_title = r.data.u_song_title;					
     });

	}

 

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);
	}
		
	// get the sys_id of the current gig from the URL
	data.gigSysId = $sp.getParameter("sys_id");
	console.log(input.gigSys_Id); // sys_is of your record
	
	// save the song to the gig in the m2m table
	if (input.action == 'saveSongs'){
    for(var indx in input.songs){
		  var addSong = new GlideRecord('x_120100_band_m2m_set_list');
			  addSong.initialize();
				addSong.gigs=data.gigSysId;
				addSong.songs=input.songs[indx];
				addSong.insert();
			console.log(input.songs); // should be your list of sys_ids for the song
			}
			}
		
})();

 

 

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

 

 

 

Can I just say a massive thanks to everyone here. 

I have it working now AND have the filters reading off the sys_ID from URL so the sets the songs go into for the gig work. 

I love this place, everyone is so helpful. 

Chris this is the second time you have come to my aid, so thank you very much!

find_real_file.png