Edit in JSFiddle

/*
 rename comare-item to compareItem
 Note: one-way-binding does not exactly behave as expected. itmes passed to comparePreview are one-way-bound but act like two-way-bound
 Open Questions: How can I control input[type=checkbox] to reflect the model bound to ng-checked properly and not to ignore it completely on click? I switched over to ng-model-binding which forces me to overwrite the set value in case maxSelections has been already exceeded rather than just check it before and update the model afterwards. 
*/

angular.module('app.compare', [])
  
  .constant("PERSISTANCE_KEY", 'compareManager.items')
  
  .factory('localPersist', function(){
      return {
        get: get,
        set: set,
        remove: remove
      };
      
      function get(key) {
        return localStorage.getItem(key);
      }
      
      function set(key, value) {
        localStorage.setItem(key, value);
      }
      
      function remove(key) {
        localStorage.removeItem(key);
      }
  })
  
  .directive('compareManager', function(localPersist){
    return {
      restrict: "A",
      bindToController: true,
      controllerAs: 'compareManager',
      controller: function(){
        var vm = this,
            maxAmountSelectable = 3;
        
        vm.items = {}; // list of all comparables
        vm.selection = []; // Map of the IDs of all selected comparables that will be persisted
        
        /*
         * called once an item needs to register itself so the manager can keep track of the viewmodel
         */
        vm.registerItem = function(item){
          // restore persisted state
          if (vm.selection.indexOf(item.id) !== -1) {
            item.selected = true;
          }
          
          vm.items[item.id] = item;
        }
        
        /*
         * delegate model-update to the owning controller
         */
        vm.onUpdateItem = function(item){
          if (item.selected === true) {
            vm.selection.push(item.id);
          } else {
            vm.selection.splice(vm.selection.indexOf(item.id), 1);
          }
          
          if (vm.selection.length > maxAmountSelectable) {
            item.selected = false;
            vm.selection.splice(vm.selection.indexOf(item.id), 1);
          }
       
          persistState();
        }
        
        activate();
        
        function activate(){
          //resetState();
          loadState();
        }
        
        function persistState(){
          localPersist.set('compareManager.items', JSON.stringify(vm.selection));
        }
        
        function loadState(){
          // restore persisted items
          var items = JSON.parse(localPersist.get('compareManager.items'));

          if (items === null) {
            return;
          }
          
          vm.selection = items;
        }
        
        function resetState(){
          localPersist.remove('compareManager.items');
        }
      }
    }
  })
  
  /**
   * compareItem
   * Register a comparable and report user invoked 
   * changes to the managing controller
   */
  .directive('compareItem', function(){
    return {
      restrict: "A",
      bindToController: {
        price:    '@compareItemPrice',
        name:     '@compareItemName',
        id:       '@compareItemId',
        register: '&compareItemOnRegister',
        onUpdate: '&compareItemOnUpdate'
      },
      scope: true,
      controllerAs: 'compareItem',
      controller: function(){
        var vm = this;
        
        vm.item = {};
        
        vm.onInit = function(){
          vm.item = {
            id: vm.id,
            name: vm.name,
            price: vm.price,
            selected: false
          }
          
          vm.register({item: vm.item});
        }

        /*
         * delegate model-update to the owning controller
         */
        vm.onChange = function(){
          vm.onUpdate({item: vm.item});
        }.bind(this);
      },
      link: function(scope){
        scope.compareItem.onInit();
      }
    }
  })
  
  
  /**
   * comparePreview
   * Show a list of selected comparables and offers a deselection-action
   * which will be then handled in the onUpdate-callback
   */
  .directive('comparePreview', function(){
    return {
      restrict: "A",
      bindToController: {
        items:        '<comparePreview',
        onUpdate:     '&compareItemOnUpdate',
        selection: '=compareItemsSelection',
      },
      scope: true,
      controllerAs: 'comparePreview',
      controller: function(){
        
        var vm = this;
        vm.isSelected = function(){
        console.log('isSelected')
          return true;
        }
        /*
         * delegate model-update to the owning controller
         */
        vm.deselect = function(item){
          item.selected = false;
          vm.onUpdate({item: item});
        }.bind(this);
      }
    }
  });
<main ng-app="app.compare" compare-manager>
  <ul>
    <li compare-item compare-item-on-register="compareManager.registerItem(item)" compare-item-price="9,99" compare-item-name="item 1" compare-item-id="1" compare-item-on-update="compareManager.onUpdateItem(item)">
      <input type="checkbox" ng-model="compareItem.item.selected" ng-change="compareItem.onChange()" /> item 1
    </li>
    
    <li compare-item compare-item-on-register="compareManager.registerItem(item)" compare-item-price="9,99" compare-item-name="item 2" compare-item-id="2" compare-item-on-update="compareManager.onUpdateItem(item)">
      <input type="checkbox" ng-model="compareItem.item.selected" ng-change="compareItem.onChange()" /> item 2
    </li>
    
    <li compare-item compare-item-on-register="compareManager.registerItem(item)" compare-item-price="9,99" compare-item-name="item 3" compare-item-id="3" compare-item-on-update="compareManager.onUpdateItem(item)">
      <input type="checkbox" ng-model="compareItem.item.selected" ng-change="compareItem.onChange()" /> item 3
    </li>
    
    <li compare-item compare-item-on-register="compareManager.registerItem(item)" compare-item-price="9,99" compare-item-name="item 4" compare-item-id="4" compare-item-on-update="compareManager.onUpdateItem(item)">
      <input type="checkbox" ng-model="compareItem.item.selected" ng-change="compareItem.onChange()" /> item 4
    </li>
  </ul>
  
  <div compare-preview="compareManager.items" compare-items-selection="compareManager.selection" compare-item-on-update="compareManager.onUpdateItem(item)" class="comparePreview">
    <ul class="comparePreview__list">
      <li class="list__item" ng-repeat="itemId in comparePreview.selection">
        {{itemId}}<br>
        {{comparePreview.items[itemId].name}}
        <button ng-click="comparePreview.deselect(comparePreview.items[itemId])">[x]</button>
      </li>
    </ul>
  </div>
</main>
.comparePreview .list__item { display: inline-block; }