Header menu on new Service portal

Chad31
Mega Expert

Ok I have seen many post on the header menu being cloned and followed the directions in threads such as Service Portal Header Menu Issue

Note: I am not used to working with angular and am strictly going off articles read. I may be missing something small.

What I am trying to accomplish:

  •         Change the cart button to redirect to a custom widget for the cart.

What I have done.

</a>

<ssp-dropdown-tree ng-if="mi.type == 'menu' && mi.items.length" items="mi.items" />

/*! RESOURCE: /scripts/app.$sp/directive.spDropdownTree.js */  

/* angular.module('sn.$sp').directive('spDropdownCustom',   */  

function () {  

return {  

restrict: 'E',  

scope: {items: '='},  

replace: true,  

template: '<ul class="dropdown-menu">' +  

'<li ng-repeat="mi in items" style="min-width: 20em;" ng-class="{\'dropdown-submenu\': mi.type == \'menu\', \'dropdown-menu-line\':$index < items.length - 1}" ng-include="getURL()">' +  

'</ul>',  

link : function(scope, element, attrs, controller) {  

scope.getURL = function() {  

return 'sspDropdownTreeTemplate';  

}  

}  

}  

};  

(function($) {  

$("body").on( "click", "a.menu_trigger", function(e) {  

var current = $(this).next();  

var grandparent = $(this).parent().parent();  

if ($(this).hasClass('left-caret') || $(this).hasClass('right-caret'))  

$(this).toggleClass('right-caret left-caret');  

grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');  

current.toggle();  

$(".dropdown-menu").each(function(i, elem) {  

var elemClosest = $(elem).closest('.dropdown');  

var currentClosest = current.closest('.dropdown');  

if (!elem.contains(current[0]) && elem != current[0] && (!currentClosest.length || !elemClosest.length || elemClosest[0] == currentClosest[0]))  

$(elem).hide();  

})  

e.stopPropagation();  

});  

$("body").on( "click", "a:not(.menu_trigger)", function() {  

var root=$(this).closest('.dropdown');  

root.find('.left-caret').toggleClass('right-caret left-caret');  

});  

})(jQuery);  

;

Problem:

  • First problem I have had is the links we have for 'Service Catalog' 'Request' and 'Switch to Legacy' start to load but time out and I am unable to click on anything that point. the cart and my user name do show up.... but there is no functionality to them.

It's worth noting that if I just take the OOTB header menu, clone it and add the angular ng-templates to it without any further edits the same behavior is observed. At that point if I had the angular provider directive, the same thing occurs.

Any help is appreciated. I like the new Service Portal, this part is just throwing me for a loop.

9 REPLIES 9

a


I did find the answer




I will look for what I did, I think I had missed something in the widget code that pointed to correct angular. I will copy and paste what code I have and you can see if it works for you.


There is one other thing you have to check I remember it being something about small and large but still looking for it. Ill update as soon as I remember



SSP Header Menu body HTML


<ul class="nav navbar-nav">
  <div class="header-loader" ng-show="loadingIndicator">
      <div class="hidden-xs sp-loading-indicator la-sm">
          <div></div>
          <div></div>
          <div></div>
      </div>
  </div>
  <li ng-repeat="item in data.menu.items" ng-class="{dropdown: item.items.length > 0}" ng-include="'spMenuTemplate'"></li>
  <!-- Shopping cart stuff -->
  <li ng-if="options.enable_cart && data.isLoggedIn" class="dropdown hidden-xs">
    <a href="javascript:void(0)"
            data-toggle="dropdown"
            id="cart-dropdown"
            uib-tooltip-template="'item-added-tooltip.html'"
            tooltip-placement="bottom"
            tooltip-trigger="'none'"
            tooltip-is-open="$parent.itemAddedTooltipOpen"
            title="${Cart}">
        <i class="fa fa-shopping-cart" aria-hidden="true"></i>
          <span ng-bind-html="'${Cart}'"></span>
          <span ng-if="cartItemCount > 0" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
  </a>
      <div class="dropdown-menu cart-dropdown">
          <sp-widget widget="data.cartWidget"></sp-widget>
      </div>
  </li>
  <li ng-if="options.enable_cart && data.isLoggedIn" class="dropdown visible-xs">
    <a href="?id=ssp_sc_cart"
            title="${Cart}">
        <i class="fa fa-shopping-cart" aria-hidden="true"></i>
          <span ng-bind-html="'${Cart}'"></span>
          <span ng-if="cartItemCount > 0" class="label label-as-badge label-primary sp-navbar-badge-count">{{cartItemCount}}</span>
  </a>
  </li>


  <script>
    <div ng-click="toggleCart()" class="item-added-tooltip">${Item has been added to your cart.}</div>
  </script>
</ul>






Server Script


(function(){


// build menus


var menu_id = $sp.getValue('sys_id'); // instance sys_id


var gr = new GlideRecord('sp_instance_menu');


gr.get(menu_id);


data.menu = {};


data.menu.name = gr.name.getDisplayValue();


data.menu.items = $sp.getMenuItems(menu_id);




data.isLoggedIn = GlideSession.get().isLoggedIn();


if (data.isLoggedIn)


data.cartWidget = $sp.getWidget("ssp-shopping-cart", {cartTemplate: "ssp_small_shopping_cart.html"});


})();


Client Controller


function (snRecordWatcher, $scope, spUtil, $rootScope, $timeout) {


$scope.loadingIndicator = $rootScope.loadingIndicator;


$scope.cartItemCount = 0;


$scope.itemAddedTooltipOpen = false;




$scope.$on("$sp.service_catalog.cart.count", function($evt, count) {


$scope.cartItemCount = count;


});




var cancelTooltipPromise;


$scope.$on("$sp.service_catalog.cart.add_item", function() {


$timeout.cancel(cancelTooltipPromise);




$scope.itemAddedTooltipOpen = true;


cancelTooltipPromise = $timeout(function() {


$scope.itemAddedTooltipOpen = false;


}, 3000);


});




$scope.$on('sp_loading_indicator', function(e, value) {


$scope.loadingIndicator = value;


});




$scope.toggleCart = function() {


$timeout.cancel(cancelTooltipPromise);


$scope.itemAddedTooltipOpen = false;


$timeout(function() {


$("#cart-dropdown").dropdown("toggle");


});


}




// Get list of record watchers


var record_watchers = [];


if ($scope.data.menu.items) {


for(var i in $scope.data.menu.items) {


var item = $scope.data.menu.items[i];


if (item.type == 'scripted') {


if (item.scriptedItems.record_watchers)


record_watchers = record_watchers.concat(item.scriptedItems.record_watchers);


}


if (item.type == 'filtered') {


record_watchers.push({'table':item.table,'filter':item.filter});


}


}


}




// Init record watchers


for (var y in record_watchers){


var watcher = record_watchers[y];


//console.info('Record Watcher: '+watcher.table+' : '+watcher.filter);


snRecordWatcher.initList(watcher.table, watcher.filter);


}




$scope.$on("record.updated", function(evt) {


spUtil.update($scope);


});




}



Angular Provider


/*! RESOURCE: /scripts/app.$sp/directive.spDropdownTree.js */  


/* angular.module('sn.$sp').directive('spDropdownCustom',   */  


function () {  


return {  


restrict: 'E',  


scope: {items: '='},  


replace: true,  


template: '<ul class="dropdown-menu">' +  


'<li ng-repeat="mi in items" style="min-width: 20em;" ng-class="{\'dropdown-submenu\': mi.type == \'menu\', \'dropdown-menu-line\':$index < items.length - 1}" ng-include="getURL()">' +  


'</ul>',  


link : function(scope, element, attrs, controller) {  


scope.getURL = function() {  


return 'spDropdownTreeTemplate_custom';  


}  


}  


}  


};  


(function($) {  


$("body").on( "click", "a.menu_trigger", function(e) {  


var current = $(this).next();  


var grandparent = $(this).parent().parent();  


if ($(this).hasClass('left-caret') || $(this).hasClass('right-caret'))  


$(this).toggleClass('right-caret left-caret');  


grandparent.find('.left-caret').not(this).toggleClass('right-caret left-caret');  


current.toggle();  


$(".dropdown-menu").each(function(i, elem) {  


var elemClosest = $(elem).closest('.dropdown');  


var currentClosest = current.closest('.dropdown');  


if (!elem.contains(current[0]) && elem != current[0] && (!currentClosest.length || !elemClosest.length || elemClosest[0] == currentClosest[0]))  


$(elem).hide();  


})  


e.stopPropagation();  


});  


$("body").on( "click", "a:not(.menu_trigger)", function() {  


var root=$(this).closest('.dropdown');  


root.find('.left-caret').toggleClass('right-caret left-caret');  


});  


})(jQuery);  


;




spMenuTemplate


<a ng-if="item.items.length == 0 && !item.scriptedItems" ng-href="{{item.href}}" target="{{item.url_target}}">{{ item.label }}</a>


<a ng-if="item.items.length > 0" href="javascript:void(0)" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">{{ item.label }} <span class="caret"></span></a>


<ul ng-if="item.items.length > 0" class="dropdown-menu" role="menu">


      <li ng-repeat="item in item.items" ng-include="'spMenuTemplate'" />


</ul>


<a ng-if="item.scriptedItems.count > 0" href="javascript:void(0)" data-toggle="dropdown" title="{{item.hint}}">


      <span ng-bind-html="item.label"></span>


      <span ng-if="!item.scriptedItems.omitBadge" class="label label-as-badge label-primary sp-navbar-badge-count">{{item.scriptedItems.count}}</span>


</a>


<ssp-dropdown-tree ng-if="item.scriptedItems.count > 0" items="item.scriptedItems.items" />




spDropdownTreeTemplate_custom


<a ng-if="mi.type == 'link'" title="{{mi.title}}" target="{{mi.target}}" href="{{mi.href}}">


  {{mi.title | characters:60}}


</a>


<a ng-if="mi.type == 'record' && !mi.__page" title="{{mi.short_description}}" href="?id=ticket&table={{mi.__table}}&sys_id={{mi.sys_id}}">


  <span>{{mi.short_description | characters:60}}</span>


  <span class="block color-primary text-muted">


      <span class="block" style="float: right">


          <sn-time-ago timestamp="mi.sys_updated_on" />


      </span>


      {{mi.number}}


  </span>


</a>


<a ng-if="mi.type == 'record' && mi.__page" title="{{mi.short_description}}" href="?id={{mi.__page}}&table={{mi.__table}}&sys_id={{mi.sys_id}}">


  <span>{{mi.short_description | characters:60}}</span>


  <span class="block color-primary text-muted">


      <span class="block" style="float: right">


          <sn-time-ago timestamp="mi.sys_updated_on" />


      </span>


      {{mi.number}}


  </span>


</a>


<a ng-if="mi.type == 'request'" title="{{mi.short_description}}" href="?id=sc_request&table={{mi.__table}}&sys_id={{mi.sys_id}}">


  <span>{{mi.short_description | characters:60}}</span>


  <span class="block color-primary text-muted">


      <span class="block" style="float: right">


          <sn-time-ago timestamp="mi.sys_updated_on" />


      </span>


      {{mi.number}}


  </span>


</a>


<a ng-if="mi.type ='approval'" title="{{mi.short_description}}" href="?id=approval&table={{mi.__table}}&sys_id={{mi.sys_id}}">


  <span ng-if="mi.short_description">{{mi.short_description | characters:60}}</span>


  <span class="block color-primary text-muted">


      <span class="block" style="float: right">


          <sn-time-ago timestamp="mi.sys_updated_on" />


      </span>


      {{mi.number}}


  </span>


</a>


<a ng-if="mi.type == 'menu' && mi.items.length" title="{{mi.title}}" href="javascript:void(0)" class="menu_trigger right-caret">


  {{mi.title | characters:60}}


</a>


<ssp-dropdown-tree ng-if="mi.type == 'menu' && mi.items.length" items="mi.items" />=


at a glance, your code looks ok.


i have successfully cloned the header menu widget and customized it.


one other thing; In your "itscSpDropdownTreeTemplate" and   "itscSpDropdownTree", please ensure that you are referencing the cloned version of your 'header menu' widget.


spDemo4DropdownTreeTemplate___ServiceNow.jpg


demo4MenuTemplate___ServiceNow.jpg




Banners_and_Alerts_and_spDropdownCustom4___ServiceNow.jpg


Found it, Sorry for the wall of text



Under the Shopping Cart widget I had to copy it and edit a few things add the following angulars as well,   ssp_large_shopping_cart.html and small_shopping_cart.html Shown below


SSP Shopping Cart


Body HTML


<div ng-if="options.cartTemplate">


<div ng-include="options.cartTemplate"></div>




  <sp-widget widget="c.editVariablesModal" ng-if="c.editVariablesModal"></sp-widget>


  <sp-widget widget="c.saveCartModal" ng-if="c.saveCartModal"></sp-widget>


</div>




<div ng-if="!options.cartTemplate">


  <div class="alert alert-danger" role="alert">


      <strong>${Error}: </strong>


      ${Please provide a cart template to render.}


  </div>


</div>



Server script


(function() {


var m = data.msgs = {};


m.createdMsg = gs.getMessage("Created");


m.trackMsg = gs.getMessage("track using 'Requests' in the header or");


m.clickMsg = gs.getMessage("click here to view");


var userID = gs.getUser().getID();


var cart = new SPCart(input.cartName, userID);




if (input && input.action === "edit_item") {


data.editVariablesModal = $sp.getWidget('widget-modal', {embeddedWidgetId: 'sp-variable-editor', embeddedWidgetOptions: {sys_id: input.itemID, table: "sc_cart_item", isOrdering: true}});


return;


}




if (input && input.action === "update_quantity") {


var cartItemGR = new GlideRecord("sc_cart_item");


if (cartItemGR.get(input.itemID)) {


cartItemGR.setValue("quantity", input.quantity);


cartItemGR.update();


}


}




if (input && input.action === "checkout") {


cart.setSpecialInstructions(input.additionalDetails);


cart.setRequestedFor(input.cart.requested_for);


cart.setDeliveryAddress(input.deliverTo);


var request = cart.placeOrder();


data.requestData = {


number: request.getValue("number"),


table: request.getTableName(),


sys_id: request.getUniqueValue()


}


cart.setSpecialInstructions("");


cart.setRequestedFor(userID);


cart.setDeliveryAddress("");


}




if (input && input.action === "remove_item") {


var itemGR = new GlideRecord('sc_cart_item');


if (itemGR.get(input.removeItemID))


itemGR.deleteRecord();


}




if (input && input.action === "save_cart") {


var newCart = new SPCart(input.newCartName, userID);


newCart.loadCart(cart.getCartID());


}




data.sys_properties = {


twostep_checkout: gs.getProperty("glide.sc.checkout.twostep", "false") == 'true'


};




var cartID = cart.getCartID();


data.saveCartModal = $sp.getWidget('widget-modal', {embeddedWidgetId: 'sc_save_bundle', embeddedWidgetOptions: {}});




data.cart = cart.getCartObj();


data.cartItems = cart.getItems();




})();



Client Controller


function ($scope, spUtil, $location) {


var c = this;


c.m = $scope.data.msgs;


c.deliverTo = "";


c.additionalDetails = "";




$scope.$on("$sp.service_catalog.cart.update", function() {


$scope.server.update().then(function() {


$scope.$emit("$sp.service_catalog.cart.count", getItemCount());


});


});




c.updateQuantity = function(item) {


c.server.get({


action: "update_quantity",


itemID: item.sys_id,


quantity: item.quantity


}).then(function(response) {


$rootScope.$broadcast("$sp.service_catalog.cart.update");


});


}




c.triggerCheckout = function($evt, twostepCheckout) {


if (twostepCheckout) {


$location.url('?id=ssp_sc_cart');


return;


}




$evt.stopPropagation();


$evt.preventDefault();




c.checkoutInProgress = true;


c.data.action = "checkout";


c.data.deliverTo = c.deliverTo;


c.data.additionalDetails = c.additionalDetails;


c.server.update().then(function(response) {


c.data.action = null;




c.checkoutInProgress = false;


var requestData = $scope.data.requestData;


issueMessage(requestData.number, requestData.table, requestData.sys_id);


$rootScope.$broadcast("$sp.service_catalog.cart.update");


});


}




c.removeItem = function($evt, item) {


$evt.stopPropagation();


$evt.preventDefault();




$scope.server.get({


cartName: "DEFAULT",


action: "remove_item",


removeItemID: item.sys_id


}).then(function(response) {


c.data.cart = response.data.cart;


c.data.cartItems = response.data.cartItems


$rootScope.$broadcast("$sp.service_catalog.cart.update");


});


}




c.editItem = function(itemID) {


c.server.get({


itemID: itemID,


action: "edit_item"


}).then(function(response) {


var myModalCtrl;


var unregister = $scope.$on('$sp.service_catalog.cart.update', function(){


myModalCtrl.close();


});




var myModal = angular.copy(response.data.editVariablesModal);


myModal.options.afterOpen = function(ctrl){


myModalCtrl = ctrl;


};


myModal.options.afterClose = function() {


unregister();


c.editVariablesModal = null;


myModalCtrl = null;


};


c.editVariablesModal = myModal;


})


}




c.saveBundle = function() {


var saveCartModalCtrl;


var unregister = $scope.$on('$sp.service_catalog.cart.save_cart', function(){


saveCartModalCtrl.close();


});




var saveCartModal = angular.copy(c.data.saveCartModal);


saveCartModal.options.afterOpen = function(ctrl){


saveCartModalCtrl = ctrl;


};


saveCartModal.options.afterClose = function() {


unregister();


c.saveCartModal = null;


saveCartModalCtrl = null;


};


c.saveCartModal = saveCartModal;


}




c.requestedFor = {


displayValue: c.data.cart.requested_for_display_name,


value: c.data.cart.requested_for,


name: 'requested_for'


};




$scope.$on("field.change", function(evt, parms) {


if (parms.field.name == 'requested_for')


c.data.cart.requested_for = parms.newValue;


});




function issueMessage(n, table, sys_id) {


var page = table == 'sc_request' ? 'sc_request' : 'ticket';


var t = c.m.createdMsg + " " + n + " - ";


t += c.m.trackMsg;


t += ' <a href="?id=' + page + '&table=' + table + '&sys_id=' + sys_id + '">' + c.m.clickMsg + '</a>';


spUtil.addInfoMessage(t);


}




$scope.$emit("$sp.service_catalog.cart.count", getItemCount());




function getItemCount() {


return c.data.cartItems.length || 0;


}


}


ssp_large_shopping_cart.html


<div>


  <div ng-show="c.data.cartItems.length > 0" class="panel panel-primary b">


      <table id="cart" class="table table-hover table-condensed">


          <thead>


              <tr>


                  <th style="width: 52%;">${Product}</th>


                  <th style="width: 10%;">${Price}</th>


                  <th style="width: 8%;">${Quantity}</th>


                  <th style="width: 10%;">${Subtotal}</th>


                  <th style="width: 10%;"></th>


              </tr>


          </thead>


          <tbody>


              <tr ng-repeat="item in c.data.cartItems track by item.sys_id | orderBy: 'order'">


                  <td data-th="Product">


                      <div class="row">


                          <div class="col-sm-2 hidden-xs"><img ng-show="item.picture" ng-src="{{item.picture}}" alt="..." class="img-responsive item-image"/></div>


                          <div class="col-sm-10">


                              <h4 class="nomargin"><a ng-href="?id=sc_cat_item&sys_id={{item.item_id}}">{{item.name}}</a></h4>


                              <p class="hidden-xs">{{item.short_description}}</p>


                          </div>


                      </div>


                  </td>


                  <td>


                      <strong>{{item.display_price}}</strong>


                      <div ng-show="item.recurring_price > 0">+ {{item.display_recurring_price}} {{item.recurring_frequency_display}}</div>


                  </td>


                  <td data-th="Quantity">


                      <input type="number"


                                    ng-if="item.show_quantity"


                                    class="form-control text-center"


                                    ng-model="item.quantity"


                                    min="1"


                                    max="99"


                                    ng-model-options="{ updateOn: 'blur' }"


                                    ng-change="c.updateQuantity(item)">


                      <span ng-if="!item.show_quantity">-</span>


                  </td>


                  <td>


                      <strong>{{item.subtotal_price}}</strong>


                      <div ng-show="item.recurring_subtotal > 0">+ {{item.recurring_subtotal_price}} {{item.recurring_frequency_display}}</div>


                  </td>


                  <td class="actions" data-th="">


                      <button class="btn btn-info btn-sm" ng-show="item.has_options" ng-click="c.editItem(item.sys_id)"><i class="fa fa-pencil"></i></button>


                      <button class="btn btn-danger btn-sm" ng-click="c.removeItem($event, item)"><i class="fa fa-trash-o"></i></button>


                  </td>


              </tr>


          </tbody>


      </table>




      <div class="panel-footer clearfix">


          <div class="pull-right">


              <h4 class="text-bold">${Total price}: {{c.data.cart.display_subtotal}}</h4>


              <h5 class="text-bold" ng-repeat="(key, value) in c.data.cart.recurring_subtotals">+ {{value}} {{key}}</h5>


          </div>


      </div>


  </div>




  <div class="panel b" ng-show="c.data.cartItems.length > 0">


      <div class="order-details-container form-group">


          <div class="order-details requested-for-details">


              <div>


                  <label>${Requested For}</label>


                  <sn-record-picker field="c.requestedFor" table="'sys_user'" display-field="'name'" value-field="'sys_id'" search-fields="'name'" page-size="100" ></sn-record-picker>


              </div>


              <div>


                  <label>${Deliver To}</label>


                  <textarea class="form-control" ng-model="c.deliverTo"></textarea>


              </div>


          </div>


          <div class="order-details special-instructions-details">


              <label>${Special Instructions}</label>


              <textarea class="form-control" ng-model="c.additionalDetails"></textarea>


          </div>


      </div>


      <div class="panel-footer">


          <a href="?id=ssp_sc_home" name="submit" ng-click="triggerOnSubmit()" class="btn btn-default m-r-xs">${Continue Shopping}</a>


          <button ng-disabled="c.checkoutInProgress" name="submit" ng-click="c.triggerCheckout($event)" class="btn btn-primary m-l-xs pull-right">


              <span ng-show="!c.checkoutInProgress">${Checkout}</span>


              <span ng-show="c.checkoutInProgress">${Ordering...}</span>


          </button>


          <a class="btn btn-default"


                ng-click="c.saveBundle()">${Save as Bundle}</a>


      </div>


  </div>




  <div ng-show="c.data.cartItems.length == 0" class="panel panel-default b">


      <div class="panel-body">


          <div class="empty-state-content">


              <span class="fa fa-shopping-cart"></span>


              <h3>${Your shopping cart is empty}</h3>


              <p>${Once you have added items to your shopping cart, you can check out from here.}</p>


              <a class="btn btn-primary" href="?id=ssp_sc_home">${View the Catalog}</a>


          </div>


      </div>


  </div>


</div>



ssp_small_shopping_cart.html


<div class="panel">


  <div class="panel-body" ng-if="c.data.cartItems.length > 0">


      <ul class="media-list" ng-if="c.data.cartItems.length > 0">


          <li class="media" ng-repeat="item in c.data.cartItems track by item.sys_id | orderBy: 'order'">


              <div class="media-left">


                  <a ng-href="?id=sc_cat_item&sys_id={{item.item_id}}">


                      <img ng-show="item.picture" ng-src="{{item.picture}}" alt="..." class="img-responsive item-image"/>


                  </a>


              </div>


              <div class="media-body">


                  <a ng-href="?id=sc_cat_item&sys_id={{item.item_id}}"><label class="media-heading">{{item.name}}</label></a>


                  <p>{{item.short_description}}</p>


                  <p class="quantity-price">


                      <span class="quantity">{{item.quantity}}  x</span><span class="price">{{item.display_price}}</span>


                      <span class="recurring" ng-show="item.recurring_subtotal > 0">+{{item.recurring_subtotal_price}}  {{item.recurring_frequency_display}}</span>


                  </p>


                  <a href="javascript:void(0)" ng-click="c.editItem(item.sys_id)" ng-if="item.has_options">${Edit}</a>


              </div>


              <div class="media-right">


                  <div class="btn-group btn-group-sm">


                      <button type="button" class="btn btn-clear"


                                      ng-click="c.removeItem($event, item)">


                          <i class="fa fa-times-circle" aria-hidden="true"></i>


                      </button>


                  </div>


              </div>


          </li>


      </ul>


  </div>


  <div class="panel-body" ng-show="c.data.cartItems.length == 0">


      <div class="empty-state-content small-cart">


          <span class="fa fa-shopping-cart small-cart"></span>


          <h4>${Your shopping cart is empty}</h4>


          <p>${Once you have added items to your shopping cart, you can check out from here.}</p>


      </div>


  </div>


  <div ng-if="c.data.cartItems.length > 0" class="panel-footer align-right">


      <label class="subtotal">${Total price}: <strong>{{c.data.cart.display_subtotal}}</strong></label>


      <label ng-repeat="(key, value) in c.data.cart.recurring_subtotals" class="subtotal">+ {{value}} {{key}}</label>


  </div>


  <div class="panel-footer">


      <div class="btn-group btn-group-justified" role="group">


          <div class="btn-group" role="group">


              <a type="button"


                    class="btn btn-default"


                    ng-href="?id=ssp_sc_cart">${View Cart}</a>


          </div>


          <div class="btn-group" role="group" ng-if="c.data.cartItems.length > 0">


              <button ng-disabled="c.checkoutInProgress"


                              ng-click="c.triggerCheckout($event, c.data.sys_properties.twostep_checkout)"


                              class="btn btn-primary">


                  <span ng-show="!c.checkoutInProgress">${Checkout}</span>


                  <span ng-show="c.checkoutInProgress">${Ordering...}</span>


              </button>


          </div>


      </div>


  </div>


</div>


I have no idea what the issue was.



When I tried to copy your code and just change to my names of things, it was still not working.



So I gave up and used your naming conventions and copied *every*single*thing* exactly as it was (except for the link to your catalog page that wouldn't exist on my system) and now it loads fine.



I guess somewhere along the line I made a typo or something.   But at least I have a working place to start from now.



Thanks so much for the help!


Shannon


I remember how frustrating that was, Glad I could help out a bit!