Reputation: 2852
I was using AngularJs-1.0.7 and Bootstrap in my application. Recently I migrated from AngularJs-1.0.7 to AngularJs-1.2. I am using Bootstrap's Accordions and Tabs.
Html code for Tab contains <a href="#id_for_content">
as shown below.
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#firstTab" data-toggle="tab">Home</a></li>
<li><a href="#secondTab" data-toggle="tab">Profile</a></li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="firstTab">
<p>Content for first tab.</p>
</div>
<div class="tab-pane fade" id="secondTab">
<p>Content For second tab.</p>
</div>
</div>
In Angular's old versions, route change happens only if we give anchor tag like <a href="#/firstTab">
. But AngularJs-1.2 redirects <a href="#firstTab">
. It doesn't consider the /
in between #
and firstTab
. Hence while clicking on Tab it redirects to http://web_url/#/firstTab
. How to solve this issue?
I found a solution for this issue. I wrote a directive for a tag. In that directive I checked for href attribute. If it matches prevent from its default behavior. Check the following code.
app.directive('a', function() {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
if(attrs.href === '#firstTab'|| attrs.href === '#secondTab'){
elem.on('click', function(e){
e.preventDefault();
});
}
}
};
});
But the problem with this method is, I have to check each and every tab ids or accordion ids here. If I use dynamic Ids for them, its not possible to check in directive.
If you can find better solution, let us all know about it.
Upvotes: 25
Views: 36031
Reputation: 264
If you don't success with previous answers, you could try use $timeout... In this case I have used AngularUI tabs...
vm.removeUserTab = function (user) {
$timeout(function () {
vm.activeTab = 0;
var index = vm.userTabs.indexOf(user);
vm.userTabs.splice(index, 1);
});
};
Upvotes: 0
Reputation: 1
My solution: - inside app.js try adding "$locationProvider.hashPrefix('!');"
.config(['$stateProvider', '$urlRouterProvider', '$httpProvider', '$locationProvider',
function($stateProvider, $urlRouterProvider, $httpProvider, $locationProvider) {
$stateProvider
.state('menu', {
url: '/',
cache: false,
abstract: true,
templateUrl: 'static/www/templates/menu.html'
})
.state('menu.main_page', {
url: 'app/main',
cache: false,
views: {
'menuContent': {
templateUrl: 'static/www/templates/mainpage.html',
controller: 'MainCtrl'
}
}
})
$locationProvider.hashPrefix('!');
$urlRouterProvider.otherwise(function ($injector, $location) {
var $state = $injector.get('$state');
$state.go('menu.mainpage');
});
}])
inside index.html try adding
<meta name="fragment" content="!">
and as Marcel said above
.directive('a', function () {
return {
restrict: 'E',
link: function (scope, elem, attrs) {
if (attrs.href && attrs.href.indexOf('#') > -1) {
elem.on('click', function (e) {
e.preventDefault();
});
}
}
};
})
that's all! works for me!
Upvotes: 0
Reputation: 13918
I would just like to let you know that there is another solution to solve this issue (without defining function in controllers).
You can create a directive that will prevent default browser's behaviour (which is actually changing URL):
var PreventDefault = function () {
var linkFn = function (scope, element, attrs) {
$(element).on("click", function (event){
event.preventDefault();
});
};
return {
restrict: 'A',
link: linkFn
}
};
and then just add the directive to each a
element responsible for toggling a tab like this:
<ul id="myTab" class="nav nav-tabs">
<li class="active"><a href="#firstTab" prevent-default data-toggle="tab">Home</a></li>
<li><a href="#secondTab" prevent-default data-toggle="tab">Profile</a></li>
</ul>
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade in active" id="firstTab">
<p>Content for first tab.</p>
</div>
<div class="tab-pane fade" id="secondTab">
<p>Content For second tab.</p>
</div>
</div>
Upvotes: 11
Reputation: 3848
Just add this to your links:
target="_self"
And you're ready ;)
Upvotes: 49
Reputation: 8539
Your solution in your question does work, but to prevent having to check for each anchor's id, change
if (attrs.href === '#firstTab'|| attrs.href === '#secondTab')
to
if (attrs.href && attrs.href.indexOf('#') > -1)
Directive:
.directive('a', function () {
return {
restrict: 'E',
link: function (scope, elem, attrs) {
if (attrs.href && attrs.href.indexOf('#') > -1) {
elem.on('click', function (e) {
e.preventDefault();
});
}
}
};
})
Upvotes: 0
Reputation: 210
try data-target="#something"
, it works fine for me in both development and production environment.
Upvotes: 21
Reputation: 46
I've been having this problem for a while now too, and I only just stumbled across this question (and your own answer). It turns out that you are almost correct with your solution, just a slight modification makes it work as you'd like.
In addition to the issue you were having with tabs, I was also encountering this problem with dropdown links -- they were navigating away from the current page when clicked, instead of dropping down the menu -- and in fact, this problem is present on any link that was designed to toggle something, i.e. with the data-toggle attribute set.
So, a slight modification to your code to check for the presence of the 'toggle' attribute solves it for me:
app.directive('a', function() {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
if(attrs.toggle){
elem.on('click', function(e){
e.preventDefault();
});
}
}
};
});
Hope this helps!
Upvotes: 1
Reputation: 446
In general you can define functions on the prototype of all scopes by using the rootscope. Add ng-click on your anchor tags and pass the $event to the rootscope handlers. Angular can send the originating event as well with ng-click:
<a ng-click="tabclick($event)">
in a run block of your module you can then set a tabClick function on $rootScope
$rootScope.tabclick = function ($event) { $event.preventDefault(); }
This will work for any scopes and you won't have to check against specific element ids.
Sample fiddle: http://jsfiddle.net/stto3703/wQe6P/
Cheers
Upvotes: 6
Reputation: 5357
You can use ng-click to call a function in your JS. In that function, use the event's preventDefault
method, and use $location
's hash
method to change the hash in your URL.
Upvotes: 2