Reputation: 91618
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
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>
Upvotes: 1
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
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