Mike Christensen
Mike Christensen

Reputation: 91618

How to get selected tab to persist when refreshing model in Angular.js

I've inherited some existing Angular.js code, which I don't know a whole lot about. A feature I've added is the ability to refresh the data in the view automatically every five seconds. I've done this by changing my init function to call itself using the $interval function:

model.init = function (token) {
    model.token = token;
    model.dataUrl = GlobScope.rootPath + "upload/checkdata/" + token;

    var loadData = function() {
        commonHelper.apiGet("api/bases/" + model.token, function(result) {
            model.bases = result.data.bases;
            model.files = result.data.files;
            model.messages = result.data.messages;
        });
    }

    // Reload data every 5 seconds
    $interval(function () {
        loadData();
    }.bind(this), 5000);

    loadData();
}

This works great, and now as data on the server changes, it'll be updated on the client within five seconds. However, there's one small problem. My view has a bunch of tabs:

<tabset>
   <tab heading="Input">
      <br />
      Some hard coded tab
   </tab>
   <tab ng-repeat="baseData in dataProcessingModel.bases" heading="{{baseData.base}}">
      Other tabs here depending on the data in the model
   </tab>
</tabset>

Unfortunately, when the data is refreshed (every five seconds), the first tab is selected again.

What's the easiest way to get the currently selected tab to remain selected, while the data continues to refresh?

One thing I've tried is to bind the active tab to some part of the model, then I can perhaps set that again when the model changes:

<tab ng-repeat="baseData in dataProcessingModel.bases" heading="{{baseData.base}}" active="dataProcessingModel.activeTab == baseData.base">

Then in the loadData function:

var defaultTab = 'Input';

var loadData = function() {
    commonHelper.apiGet("api/bases/" + model.token, function(result) {
        model.activeTab = defaultTab;
        model.bases = result.data.bases;
        model.files = result.data.files;
        model.messages = result.data.messages;
    });
}

Next, I'd somehow have to change defaultTab every time a new tab is selected. However, with this code, tabs become completely broken. Clicking on a tab does nothing.

Is there a simple approach to this? I dug through the tab docs and couldn't find anything of intested.

Upvotes: 0

Views: 1680

Answers (3)

New Dev
New Dev

Reputation: 49590

The issue is with how ng-repeat tracks items. In your case, each "repeatable" item - baseData - is an object, and it is a different object every time you reload the items, so, ng-repeat has no way of knowing which is which. So, when you reload, completely new tab directives are created by ng-repeat and so active tab is lost.

This is when track by is used to tell ng-repeat how to track objects. It seems that in your case tracking by $index is most suitable (if you have some other immutable property to track the object by, you could use that as well, ex. baseData.id)

<tabset>
  <tab ng-repeat="baseData in dataProcessingModel.bases track by $index"
       heading="{{baseData.base}}">
    {{baseData.content}}
  </tab>
</tabset>

Demo

Upvotes: 1

J-Dizzle
J-Dizzle

Reputation: 3191

If you modify the loadData() function to accept an optional parameter, you can trigger the component to scroll where you want it to sometimes, and scroll to default if you pass in no parameters.

var defaultTab = 0;
var loadData = function(activeTab = defaultTab) {
    commonHelper.apiGet("api/bases/" + model.token, function(result) {
        model.activeTab = activeTab;
        // scrollTo(activeTab)
        model.bases = result.data.bases;
        model.files = result.data.files;
        model.messages = result.data.messages;
    });
};

Upvotes: 0

Dilip Tirumala
Dilip Tirumala

Reputation: 371

var defaultTab = 'Input'; // set this tab to currentTab before you call loadData()

  $interval(function () {
        loadData(defaultTab);
    }.bind(this), 5000);

    loadData(defaultTab);

var loadData = function(defaultTab) {
    commonHelper.apiGet("api/bases/" + model.token, function(result) {
        model.activeTab = defaultTab;
        model.bases = result.data.bases;
        model.files = result.data.files;
        model.messages = result.data.messages;
    });

}

Upvotes: 0

Related Questions