JSFiddle - React, Tailwind, and code Playground

by Blake Dietz

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.13/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
<div  ng-app="exampleApplication" ng-controller="selectionController">
    <!-- Template for single selection directive -->
	    <script type="text/ng-template" id="selection-directive.tpl.html">
	       <div>
			    <select name="" id=""
			    		ng-model="selectedItem"
			    		ng-options="selectable.name for selectable in selectableItems"
			    		ng-change="changeHandler(selectedItem, currentItem)">
			        <option value="">
			            {{selectedItem.name}}
				    </option>
				</select>
	    		<button ng-click="removeHandler(selectedItem)">Remove</button>
			</div>
	    </script>

		<div
			ng-repeat="selectedItem in selectedItems"
			selected-item="selectedItem"
			selectable-items="selectableItems"
			change-handler="replaceItemInSelectedItemsWithNewlySelectedItem"
			remove-handler="removeCurrentSelection"
		>
		</div>

		<div ng-show="selectableItems.length">
		    <select name="" id="" ng-model="aSelection" ng-options="selectable.name for selectable in selectableItems" ng-change="selectUnselectedItem(aSelection)">
		        <option value="">
		            Select something
		        </option>
		    </select>
		</div>
</div>

JavaScript

angular.module( 'exampleApplication', [] )
  .controller( 'selectionController', function( $scope )
  {
    $scope.selectedItems = _.range( 0, 24 )
      .map( function( number )
      {
        return {
          "name": number
        }
      } );
    $scope.selectableItems = [
    {
      "name": 24
    } ];
    $scope.aSelection;

    $scope.replaceItemInSelectedItemsWithNewlySelectedItem = function( selectable, current )
    {

      var currentIndex = _.findIndex( $scope.selectedItems,
        function( item )
        {
          return current.name === item.name;
        } );

      var itemToSwitchWithCurrentSelection = removeFromSelecableItems( selectable );
      var currentSelection = removeFromSelectedItems( current );

      $scope.selectedItems.splice( currentIndex, 0, itemToSwitchWithCurrentSelection );
      addToSelectableItems( currentSelection );
    };

    $scope.selectUnselectedItem = function( selectable )
    {

      var selectedItem = removeFromSelecableItems( selectable );

      $scope.selectedItems.push( selectedItem );
      $scope.aSelection = null;
    };

    $scope.removeCurrentSelection = function( currentlySelected )
    {
      var selectionToRemove = removeFromSelectedItems( currentlySelected );

      addToSelectableItems( selectionToRemove );
    };

    function removeFromSelectedItems( itemToRemove )
    {
      return _.remove( $scope.selectedItems,
        function( item )
        {
          return itemToRemove.name === item.name;
        } )[ 0 ];
    }

    function removeFromSelecableItems( itemToRemove )
    {
      return _.remove( $scope.selectableItems,
        function( item )
        {
          return itemToRemove.name === item.name;
        } )[ 0 ];
    }

    function addToSelectableItems( itemToAdd )
    {
      $scope.selectableItems.push( itemToAdd );
      $scope.selectableItems = _.sortBy( $scope.selectableItems, 'name' );
    }

  } )
  .directive( 'selectedItem', function()
  {

    return {
     ...