We have a series of notifications and want to make the overall item clickable to the related item. This has been implemented using ui-sref and functions correctly. However, within that, there are to be a series of nested links that go to other relevant information. The problem at the moment is this parent ui-sref overrides all of these links. I've tried implementing these nested links as standard anchor and ui-sref but it has the same effect. So the hyperlink shows correctly, and when clicking on it, it goes to it for a split second, then reverts back to the ui-sref link.
Here is a code example:
<div class="NotificationItemBalanced">
<div class="notificationItem" ui-sref="community.act({slug: slug, id: id})">
<div class="messageBodyWrapper">
<span class="messageText"><strong><a ui-sref="user.posts({username: username})"></a></strong> commented on your post</span>
</div>
</div>
</div>
Is this related to the ui-sref or is there a specific setting in the routes to fix this?
Thanks
Just create a directive like:
myApp.directive('preventBubbling', function() {
return {
link: function($scope, element) {
element.on("click", function(e) {
e.stopPropagation();
});
}
};
});
And add it to your inner links:
<a ui-sref="user.posts({username: username})" prevent-bubbling></a>
Basically, when you click on a nested element, the click event bubbles up to the DOM tree. So we are simply stopping it to propagate.
https://developer.mozilla.org/en/docs/Web/API/Event/stopPropagation
Update
Also, if your inner links are inheriting properties from parent ui-sref then you should use ui-sref-opts as well:
<a ui-sref="user.posts({username: username})" ui-sref-opts="{inherit: false}" prevent-bubbling></a>
Related
When a link is clicked in the app navigation a dropdown with ui-view content shows below each respective link.
The HTML:
<div class="sc-dash-header">
<ul>
<li>
<a class="navbar-brand" show-nav-popup href="">download</a>
<div id="nav-download-progress" class="dash-hdr-popup" ng-show="showPopup">
<div ui-view="hdr-download-progress"></div>
</div>
</li>
<li>
<a class="navbar-brand" show-nav-popup href="">add</a>
<div id="nav-add" class="dash-hdr-popup" ng-show="showPopup">
<div ui-view="hdr-add-content"></div>
</div>
</li>
<li>
<a class="navbar-brand" show-nav-popup href="">enter pin</a>
<div id="nav-unlock" class="dash-hdr-popup" ng-show="showPopup">
<div ui-view="hdr-unlock"></div>
</div>
</li>
</ul>
</div>
I've included an ng-show attribute to open the dropdown when $scope.showPopup is set to true.
To achieve this I've created a custom directive with an on click called show-nav-popup.
The JS:
.directive('showNavPopup', function () {
return {
restrict: 'A',
// scope: {},
link: function(scope, el, attrs) {
el.on('click', function(){
scope.$apply(function () {
scope.showPopup = true;
});
console.log(scope);
});
}
};
});
The above works, but the dropdown opens on each element.
Question: I need to isolate the scope, so on each click, only the respective dropdown appears. I uncomment the line // scope: {} - but this doesn't work..
Angularjs n00b here - any help would be much appreciated
Having an isolate scope in this situation wouldn't fix the problem. There are a ton of ways to achieve what you want though. One of which is to assign each show-popup-nav an id, turn $scope.showPopup into an array, and keep an individual true/false for each id. Then for each ng-show, you look at the index corresponding to each id for the true/false value.
I coded it up on that guy's Plunker, working as you expect: http://plnkr.co/edit/CSikLIiuPNT9dfsfZfLk
EDIT: I should say, you COULD use an isolate scope to fix this, but that would require a lot of changes to your DOM, as the ng-show directive is a sibling to your show-popup-nav, and not a child.
When you create the isolate scope, the scope applies to the element that your directive is applied to, and it's child elements. In this case that's just the anchor tag:
<a class="navbar-brand" show-nav-popup href="">download</a>
You are using an ng-show on a tag that is a sibling to the anchor tag:
<div id="nav-download-progress" class="dash-hdr-popup" ng-show="showPopup">
The sibling is not part of the isolate scope, and so it never notices that the value of showPopup has changed.
The ng-show would work if it were applied to a DOM element that was a child of the anchor tag.
EDIT
One way to make this work would be to wrap your two siblings in a parent tag, and use the directive on the parent:
<div show-nav-popup>
Download
<div ng-show="showPopup"></div>
</div>
Then you'd need to modify your directive's code to find the anchor tag and apply the click handler.
You might instead try a completely different approach as suggest in the other answer by #Bill Bergquist
I display a list of items through ng-repeat
<div ng-repeat="{item in items}" >
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
I have an add where i click and add new items..I display through ng-repeat in a div and that contains scroll..Whenever i add a new item the scroll bar stand still and i can see the newly added item by scrolling down only.
I used ng-focus="{$last}" to set focus on last item but it didnt work.
I need to set focus on last element in ng-repeat even i have 50 elements in div.
Plss help me in this..
I'd recommed using a directive to achieve this behaviour.
module.directive('setFocus', function(){
return{
scope: {setFocus: '='},
link: function(scope, element){
if(scope.setFocus) element[0].focus();
}
};
});
And on your HTML:
<div ng-repeat="{item in items}" set-focus="$last">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
When you load the page, .focus() is ran on the last element.
If you add an element, .focus() is ran on that new last element.
Now your problem lies on which elements are focusable across different browsers. I suggest you check which HTMLElement can receive focus.
So, you may want to add a hidden focusable element inside your div, and modify the directive to focus on that, or maybe add a tabindex attribute to your ng-repeat div. (tabindex="some number other than -1")
<div ng-repeat="{item in items}" set-focus="$last" tabindex="0">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
</div>
I hope this helps!
To clarify: ng-focus is used to specify behaviour ON focus, not to trigger focus on the element.
You can use $anchorScroll in AngularJS.
Just place a link (< a> < /a>) at the bottom of your div with the id="bottom" and ng-hide="true", so you dont actually see the link.
<div id="scrollArea" ng-repeat="item in items">
<h3>{{item.name}}</h3>
<h3>{{item.price}}</h3>
<h3>{{item.date}}</h3>
<a id="bottom"></a>
</div>
<button type="button" ng-click="addNewItem" value="Add"/>
When you click on your "add" button or whatever, call a function in the Controller that leads you to the bottom link with the id="bottom".
$scope.addNewItem = function() {
//Add new item here...
//After adding item, go to bottom:
$location.hash('bottom');
$anchorScroll();
};
You can read more about this on the Documentaion of AngularJS:
Documentaion of $anchorScroll.
I am working on a website that displays numerous articles. Each article has a comment section. I have effectively been able to recursively write the comments to the DOM with recursion inside an ng-repeat. However, I need to be able to click on a respond button on any of the comments (they display in a nested fashion) and for a div to be inserted beneath the clicked button. This div would contain a text area for the comment they want to submit and a button. When this second button is clicked, the controller will save the comment to the database. I initially wanted to do this by directly manipulating the DOM from the controller. However, after further research, that would be in direct violation of the MVC/MVW pattern. I believe the correct answer is to create a custom directive. Please give me some insight on how to correctly do this. Any and all information would be very helpful. Thanks in advance.
If you want to add response div dinamically:
<div ng-repeat="article in articles" id="article-{{$index}}">
<p>{{article.content}}</p>
<button ng-click="addAnswer($index)">Add Answer</button>
</div>
js:
myApp.controller("articlesController", function($compile){
$scope.addAnswer = function (index) {
var div = $("<div></div>");
var input = $("<input type='text' ng-model='article.response'></input>");
div.append(input);
var button = $("<button>Send</button>");
button.attr("ng-click", "sendResponse(article)");
$compile(div)($scope);
$("#article-" + index).append(div);
};
});
You don't really need to make a directive to achieve this.
html:
<div ng-repeat="article in articles">
<p>{{article.content}}</p>
<input type="text" ng-model="article.response"></input>
<button ng-click="sendResponse(article)">Send</button>
</div>
js:
myApp.controller("articlesController", function($http){
$scope.sendResponse = function (article) {
console.log(article.response);
$http.post(url, article);
};
});
Of course, you can do it better by hidding input and send button, and show it after user clicks over an answer button.
I'm using snap.js with AngularJS using the angular-snap.js directive.
https://github.com/jtrussell/angular-snap.js
I'm also using Andy Joslin's angular-mobile-nav.
I'm wondering where I should store the code for the menu:
<snap-drawer>
<p>I'm a drawer! Where do I go in the angular code?</p>
</snap-drawer>
Because this isn't a unique page within the angular-mobile-nav, I'm currently putting the on every page and just using a directive that contains all my menu code/html.
Seems like this could be inefficient as it is loading a new directive on each page, right? Any idea on how to do this better?
Thanks!
So this is what I've done (I also use angular-mobile-nav and angular-snap.js).
This is my HTML Code
<body ng-app="MyApp">
<div snap-drawer>
<ul class="list">
<li ng-repeat="item in sidebar.items" ng-i18next="{{item.name}}" ng-tap="snapper.close();go(item.link)"></li>
</ul>
</div>
<div id="container" snap-content snap-options="snapOpts">
<div mobile-view=""></div>
</div>
</body>
please note that go() is the function to change the page and that I'm using ng-i18next to translate my items. Also ng-tap is a directive which listens for touch events instead of mouse events. With Angular >1.1.5 there's a mobile module, so my ng-tap directive won't be needed anymore.
And by using $rootScope I can put items in the sidebar:
$rootScope.sidebar = {
items: [
{
name: 'item_one',
link: 'page_one'
},
...
]
};
So if you want to change the items in the sidebar, simply override $rootScope.sidebar (not $scope.sidebar) in your controller ;)
If you don't like two animations happen at the same time, you could write a function, which waits for the sidebar to close and then change the page. It could look like this:
$rootScope.waitThenGoTo = function (page, time) {
time = time || 200;
$timeout(function () {
$navigate.go(page);
}, time);
};
If you have still question, please comment. I'll try to update this answer as soon as possible.
I am somewhat new to using Angular and AngularStrap directives. I need to use the tab directive with static markup like the example:
<div data-fade="1" bs-tabs>
<div data-title="'Home'"><p>Static tab content A</p></div>
<div data-title="'Profile'"><p>Static tab content B</p></div>
</div>
On another part of the page I would like to display a div only when the first tab is selected. The div is not part of the tabs, but is in the same overall controller. How can I show/hide this div based on the selected tab?
Something like this?
<div ng-show="???? active tab stuff here ????">Home tab is selected</div>
Thanks for any help.
As shown in the example on the AngularStrap page the active tap is stored in
tabs.activeTab
So you can use this property to conditionally show display something else like so
<div ng-show="tabs.activeTab == 0">The first tab is active</div>
UPDATE
Even with non object tabs you can just bind a model against the bs-tabs to store the active ID like so:
<div data-fade="1" ng-model="tabs.activeTab" bs-tabs>
Here is an updated plnkr. (Click on the 3rd tab and see the 'Test' text appear)
I found somewhat of a hack to resolve this issue for now. This does not seem like the best approach, so if someone has a better idea, please share.
I realized that the bsTabs directive is creating data-toggle attributes for each tab. By watching the data-toggle shown event, I am able to recognize the tab change and display the div. The controller code looks like this:
$scope.HomeTabSelected = true;
function watchTab() {
$('a[data-toggle="tab"]').on('shown', function (e) {
$scope.$apply($scope.HomeTabSelected = (e.target.innerHTML == "Home"));
})
}
setTimeout(watchTab, 2000); // setTimeout necessary to allow directive to render
and the HTML div uses ng-show.
<div ng-show="HomeTabSelected">Home tab is selected</div>