{"id":7798,"date":"2015-10-27T09:00:52","date_gmt":"2015-10-27T09:00:52","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2015\/10\/27\/preserving-data-in-dynamic-tabs-angularjs-angular-material-ui-grid-open-source-projects-callemall-material-ui\/"},"modified":"2015-10-27T09:00:52","modified_gmt":"2015-10-27T09:00:52","slug":"preserving-data-in-dynamic-tabs-angularjs-angular-material-ui-grid-open-source-projects-callemall-material-ui","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2015\/10\/27\/preserving-data-in-dynamic-tabs-angularjs-angular-material-ui-grid-open-source-projects-callemall-material-ui\/","title":{"rendered":"Preserving data in dynamic tabs &#8211; AngularJS\/Angular Material\/UI-grid-open source projects callemall\/material-ui"},"content":{"rendered":"<p>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 &#8211; such as list of sales, list of customers, so on so forth.<\/p>\n<p>A sample of my app.js (containing configuration) reads as follows -:<\/p>\n<pre><code>$stateProvider\n\n    .state('login', {\n      url: '\/login',\n      templateUrl: 'views\/login.html',\n      controller: 'LoginCtrl'\n    })\n\n    .state('base', {\n      templateUrl: 'views\/base.html',\n      controller: function BaseCtrl($scope, SaleTabs){\n        $scope.tabData = SaleTabs.data;\n\n        $scope.saleTabSelected = function(tab){\n          SaleTabs.saleTabSelected(tab);\n        };\n      }\n    })\n\n    .state('base.sale', {\n      url: '\/sale\/:saleId',\n      views: {\n        'main-view': {\n          templateUrl: 'views\/sale.html',\n          controller: 'SaleCtrl'\n        }\n      }\n    })\n\n    .state('base.sales', {\n      url: '\/sales',\n      views: {\n        'main-view': {\n          templateUrl: 'views\/sales.html',\n          controller: 'SalesCtrl'\n        }\n      }\n    })\n<\/code><\/pre>\n<p>The <code>base.sale<\/code> state is the main view. Now I need to implement a couple of things -:<\/p>\n<ul>\n<li>\n<p>When <code>base.sale<\/code> 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 <code>md-tab<\/code>. Basically a tab needs to open if I go to this state via the URL.<\/p>\n<\/li>\n<li>\n<p>When I create a sale from the <code>base.sale<\/code> view, I trigger a state change to <code>\/sale\/:saleId<\/code>. I need this state to open in a new tab.<\/p>\n<\/li>\n<li>\n<p>When switching between tabs, I need any data that I changed in that tab&#8217;s state to be preserved &#8211; this is crucial in differentiating between navlinks which simply load state on clicking, and tabs.<\/p>\n<\/li>\n<\/ul>\n<p>Since I needed the tabs functionality in both my <code>BaseCtrl<\/code> and my <code>SaleCtrl<\/code>, I decided to make it a service. This is what it looks like currently -:<\/p>\n<pre><code>angular.module('myApp')\n  .factory('SaleTabs', [\n    '$state',\n    function($state){\n      var SaleTabs = this;\n      SaleTabs.data = {\n        tabs: [],\n        selectedIndex: 0\n      };\n\n      this.addSaleTab = function(title, saleId){\n        \/\/ Check if our tab already exists\n        var result = SaleTabs.data.tabs.filter(function(tab){\n          return tab.saleId === saleId;\n        });\n\n        if(result.length &gt; 0){\n          \/\/ If it exists, select it\n          SaleTabs.saleTabSelected(result[0]);\n        } else {\n          \/\/ If not, create it\n          var tab = {\n            title: title,\n            saleId: saleId,\n            index: SaleTabs.data.selectedIndex\n          };\n          SaleTabs.data.selectedIndex += 1;\n\n          SaleTabs.data.tabs.push(tab);\n          SaleTabs.saleTabSelected(tab);\n        }\n      };\n\n      SaleTabs.removeSaleTab = function(tab){\n        var index = SaleTabs.data.tabs.indexOf(tab);\n        SaleTabs.data.tabs.splice(index, 1);\n        SaleTabs.data.selectedIndex = index - 1;\n      };\n\n      SaleTabs.saleTabSelected = function(tab){\n        SaleTabs.data.selectedIndex = tab.index;\n        $state.go('base.sale', {saleId: tab.saleId});\n      };\n\n      return SaleTabs;\n    }\n  ]);\n<\/code><\/pre>\n<p>Ignoring the erroneous logic for switching between tabs (that&#8217;s a topic for another post I suppose), this is how I&#8217;ve written my tabs definition in the template for my base controller (<code>BaseCtrl<\/code>, in the app.js snippet above) -:<\/p>\n<pre><code>\n  \n    \n      {{ tab.title }}\n      <i class=\"mdi mdi-close-circle\" ng-click=\"removeSaleTab(tab)\" role=\"button\">\n      <\/i>\n    \n  \n\n<\/code><\/pre>\n<p>Note that I had to use <code>ng-click<\/code> instead of <code>md-on-select<\/code> because it doesn&#8217;t seem to work in angular-material 0.8.3 (I will be upgrading soon to 0.9.4). The <code>mdi<\/code> bit is the Material Design Icons library in action &#8211; I was trying to create closable tabs.<\/p>\n<p>Currently, I am able to create a tab when a sale is created from the <code>base.sale<\/code> view, but all the tab does is function like a navlink. How would I go about achieving the goals listed above?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &#8211; such as list of sales, list of customers, so on [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7798","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/7798","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=7798"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/7798\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=7798"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=7798"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=7798"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}