1

I am beginning to run into this problem a lot. The scenario is that I have a partial that I would like to reuse. The problem is, I would have to overwrite my previous data in the scope in order for the new data to show up in the partial. I would like to know how people get around this.

Here is an example:

I have tabs that all use $scope.pebbles and share the same partial. For each tab, I would like different data to be populated. So naturally, I would just make a new request for data and store it back into the variable to change the data, for example: $scope.pebbles = getPebbles(color). The problem with this is that I would have to make a new request each time I change the tab. Is there a better way around this without having a huge partial?

overview.html:

<tab>
    <tab-heading>
        <i class="icon-bell"></i> All
    </tab-heading>
    <div class="tab-content">
        <div ng-include="'views/partials/_pebbles.html'"></div>
    </div>
</tab>
<tab ng-repeat="color in colors">
    <tab-heading ng-click="tab(color)">
        {{color}} 
    </tab-heading>
    <div class="tab-content"> 
        <div ng-include="'views/partials/_pebbles.html'"></div>
    </div>
</tab>

_pebbles.html:

 <table class="table table-striped table-bordered bootstrap-datatable datatable">
    <thead>
        <tr>
            <th>Pebble Name</th>
            <th>Pebble Type</th>
        </tr>
    </thead>   
    <tbody>
        <tr ng-repeat="pebble in pebbles">
            <td>{{pebble.name}}</td>
            <td>{{pebble.type}}</td>
        </tr>
    </tbody>
</table>

Controller:

$scope.colors = ['blue','red','orange','purple']
$scope.pebbles = getPebbles() // http factory, makes a request for data

$scope.tab = function (color) {
    $scope.pebbles = getPebbles(color)
}
Strawberry
  • 66,024
  • 56
  • 149
  • 197

4 Answers4

2

A little bit of simplistic runtime caching will get you going:

Controller:

$scope.colors = ['blue','red','orange','purple']
// $scope.pebbles = getPebbles(); // http factory, makes a request for data
$scope.pebbles = [];

$scope.tab = function (color) {
  $scope.selectedColor = color;
  $scope.pebbles[color] = $scope.pebbles[color] || getPebbles(color);
}

Template:

<table class="table table-striped table-bordered bootstrap-datatable datatable">
  <thead>
    <tr>
      <th>Pebble Name</th>
      <th>Pebble Type</th>
    </tr>
  </thead>   
  <tbody>
    <tr ng-repeat="pebble in pebbles[selectedColor]">
      <td>{{pebble.name}}</td>
      <td>{{pebble.type}}</td>
    </tr>
  </tbody>
</table>
Stewie
  • 60,366
  • 20
  • 146
  • 113
2

In the angular world, the way to share data across controllers / views is to use services. They persist between controllers.

I was about to write a nice answer, but I think the answer to this question is already complete.

Better design for passing data to other ng-view's and persisting it across controllers

Community
  • 1
  • 1
Galdo
  • 945
  • 6
  • 12
0

Stewie's answer gets the job done effectively, but I wanted to suggest another design that you could potentially use.

Right now, your controller seems to be mixing two concerns; the management of your colors (tabs), and the management of the pebbles of a given color (tab contents).

What you could do instead is to have two controllers, each managing one of these concerns. This allows you to have controllers with clear cut roles and keeps your controllers slim. In the long run, it will keep your code maintainable as you add more functionality to your controllers. Here is a plunker where I have created an overviewController (dealing with tab management) and a pebblesController (dealing with individual tab content).

http://plnkr.co/edit/1ZP92VX0RljrsrfPpt0X?p=preview
**I faked the server-side getPebbles() http request and created "flat" tabs since I didn't want to bother with making actual tabbing.

Things to note with this implementation; it becomes more difficult to have dynamic tab loading (having tab-content load only upon being switched to for the first time), which Stewie's run-time caching example handles very well. In my plunker, all the tab-contents are loaded up-front. If you want to keep this design pattern and have dynamic tab loading, it would probably be cleanest to support it in the tabs directive itself, but that is out of the scope of this question.

Andrew Ho
  • 583
  • 3
  • 14
0

So I'm guessing you're using Angular's UI-Bootstrap for modelling your tabs.

As Stewie suggested you could use a simple cache for caching your loaded tabs and as I understand you'd like to load your tabs on demand, when user activates them.

Checkout the little Plunkr I did, which does exactly that. I've used select expression to load the tab on change, either from cache or from backend.

The main code lives in a controller:

app.controller('PebblesCtrl', function ($scope, $http) {

  $scope.colors = ['blue', 'red', 'orange', 'purple'];
  $scope.pebbles = [];

  $scope.loadPebbles = function (color) {
    if (!$scope.pebbles[color]) {
      console.log('loading "' + color + '" pebbles');
      $http.get(color + '.json').then(function (response) {
        $scope.pebbles[color] = response.data;
      });
    }
  };
});

You can also display a place holder for your content

<tab ng-repeat="color in colors" heading="{{color}}" select="loadPebbles(color)">     
  <div ng-show="pebbles[color]">
    <div ng-include="'_pebbles.html'"></div>
  </div>
  <div ng-hide="pebbles[color]">
    Please Wait...
  </div>
</tab>

It will be replaced when the data gets returned from the service.

lpiepiora
  • 13,659
  • 1
  • 35
  • 47