Preserving data in dynamic tabs – AngularJS/Angular Material/UI-grid-open source projects callemall/material-ui

In the main view of my app, I have a section dedicated to customer information and and one section containing a (ng-)grid of products. Above the main view is a navbar which contains navlinks (not tabs, just links), to various states of the app – such as list of sales, list of customers, so on so forth.

A sample of my app.js (containing configuration) reads as follows -:

$stateProvider

    .state('login', {
      url: '/login',
      templateUrl: 'views/login.html',
      controller: 'LoginCtrl'
    })

    .state('base', {
      templateUrl: 'views/base.html',
      controller: function BaseCtrl($scope, SaleTabs){
        $scope.tabData = SaleTabs.data;

        $scope.saleTabSelected = function(tab){
          SaleTabs.saleTabSelected(tab);
        };
      }
    })

    .state('base.sale', {
      url: '/sale/:saleId',
      views: {
        'main-view': {
          templateUrl: 'views/sale.html',
          controller: 'SaleCtrl'
        }
      }
    })

    .state('base.sales', {
      url: '/sales',
      views: {
        'main-view': {
          templateUrl: 'views/sales.html',
          controller: 'SalesCtrl'
        }
      }
    })

The base.sale state is the main view. Now I need to implement a couple of things -:

  • When base.sale is loaded with a saleId (upon which it fetches all the data from the server and puts it into the customer info section and the UI grid), I want this state to be associated with a md-tab. Basically a tab needs to open if I go to this state via the URL.

  • When I create a sale from the base.sale view, I trigger a state change to /sale/:saleId. I need this state to open in a new tab.

  • When switching between tabs, I need any data that I changed in that tab’s state to be preserved – this is crucial in differentiating between navlinks which simply load state on clicking, and tabs.

Since I needed the tabs functionality in both my BaseCtrl and my SaleCtrl, I decided to make it a service. This is what it looks like currently -:

angular.module('myApp')
  .factory('SaleTabs', [
    '$state',
    function($state){
      var SaleTabs = this;
      SaleTabs.data = {
        tabs: [],
        selectedIndex: 0
      };

      this.addSaleTab = function(title, saleId){
        // Check if our tab already exists
        var result = SaleTabs.data.tabs.filter(function(tab){
          return tab.saleId === saleId;
        });

        if(result.length > 0){
          // If it exists, select it
          SaleTabs.saleTabSelected(result[0]);
        } else {
          // If not, create it
          var tab = {
            title: title,
            saleId: saleId,
            index: SaleTabs.data.selectedIndex
          };
          SaleTabs.data.selectedIndex += 1;

          SaleTabs.data.tabs.push(tab);
          SaleTabs.saleTabSelected(tab);
        }
      };

      SaleTabs.removeSaleTab = function(tab){
        var index = SaleTabs.data.tabs.indexOf(tab);
        SaleTabs.data.tabs.splice(index, 1);
        SaleTabs.data.selectedIndex = index - 1;
      };

      SaleTabs.saleTabSelected = function(tab){
        SaleTabs.data.selectedIndex = tab.index;
        $state.go('base.sale', {saleId: tab.saleId});
      };

      return SaleTabs;
    }
  ]);

Ignoring the erroneous logic for switching between tabs (that’s a topic for another post I suppose), this is how I’ve written my tabs definition in the template for my base controller (BaseCtrl, in the app.js snippet above) -:


  
    
      {{ tab.title }}
      
      
    
  

Note that I had to use ng-click instead of md-on-select because it doesn’t seem to work in angular-material 0.8.3 (I will be upgrading soon to 0.9.4). The mdi bit is the Material Design Icons library in action – I was trying to create closable tabs.

Currently, I am able to create a tab when a sale is created from the base.sale view, but all the tab does is function like a navlink. How would I go about achieving the goals listed above?