How to make a simple menu navigation in angularjs - javascript

I'm not really satisfied with what I can find. I just want a simple example of a menu system in Angularjs with hover effect and selection effect.
I understand that 'hover' effects can be done in CSS, but this is more of an exercise for me to understand angularjs better.
What I am trying to do is pretty basic stuff.
Basically I have some HTML which has some DIVs (or menu items) :
<div NavCtrl id="header">
<div class="item" ng-click="click(1)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
1
</div>
<div class="item" ng-click="click(2)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
2
</div>
<div class="item" ng-click="click(3)" ng-mouseenter="hoverIn()" ng-mouseleave="hoverOut()">
3
</div>
</div>
I want to do two things.
listen on click
listen on mouseIn and mouseOut
I understand..
It is probably nicer to do the hover effect in CSS
It is possible to do some inline logic in the HTML with angularjs
...because I want to have flow on effects from these events. A hover event needs to pull information out related to that menu item, and a click event should also be able to perform some action related to that menu item. Cheap CSS tricks are not going to solve this!
For my hover logic, I thought this would do the trick :
$scope.hoverIn = function($event){
angular.element($event.srcElement).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.srcElement).removeClass('hover')
};
However $event is undefined :( . How do I get to the element object from a mouseover event?
My click logic looks like this :
$scope.click = function(position, $event) {
elem = angular.element($event.srcElement);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
Same problem : $event is undefined. I also want to pass in the index, so that I can do something special for certain menu items.
My Fiddle is here :
https://jsfiddle.net/zxjg3tpo/5/

ng-mouseenter="hoverIn($event)"
How it works: ng-mouseenter is kinda clever and it has $event in its scope in addition to what you have (i.e. you have hoverIn). So when it parse provided expression, it launches hoverIn with event.
All work with elements, like addClass should be done in directives where you have direct access to html element. Sometimes you may need angular.element(...) but in most cases you are happy with current element. (In directive link : function(scope, element, attrs))

In angularjs you can get the event by using $event in your html code
<div class="item" ng-click="click(1,$event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
Hover Logic
$scope.hoverIn = function($event){
angular.element($event.target).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.target).removeClass('hover')
};
Click logic
$scope.click = function(position, $event) {
elem = angular.element($event.target);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
Updated Fiddle : https://jsfiddle.net/zxjg3tpo/6/
Here is another updated Fiddle where the siblings have their class removed (to make the click work correct)
https://jsfiddle.net/zxjg3tpo/9/

You missed to pass $event from html and the srcElement was wrong.
Please try the following:
HTML
<body ng-app="navTest" ng-controller="NavTestCtrl">
<div id="header">
<div class="item" ng-click="click(1, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
1
</div>
<div class="item" ng-click="click(2, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
2
</div>
<div class="item" ng-click="click(3, $event)" ng-mouseenter="hoverIn($event)" ng-mouseleave="hoverOut($event)">
3
</div>
</div>
</body>
JS Code:
var app = angular.module('navTest', [
]);
app.controller('NavTestCtrl', function ($scope, $location, $http) {
$scope.click = function(position, $event) {
elem = angular.element($event.target);
if (elem.hasClass("clicked")) {
elem.removeClass("clicked")
}else {
elem.addClass("clicked")
}
// if (position == 1) //do something etc...
};
$scope.hoverIn = function($event){
angular.element($event.target).addClass('hover')
};
$scope.hoverOut = function($event){
angular.element($event.target).removeClass('hover')
};
});

Related

probably event bubbled on wrong element in custom directive

My goal is to flip a simple element on page on mouse click. It works but not on every click. I must click several times in different places across the tile and then the tile flip.
Code is executed as I see in the console, but it looks like click on wrong elements is fired.
I have custom directive with link method:
link: function (scope, element, attrs) {
scope.hideClicked = true;
scope.showClicked = false;
scope.backClicked = function () {
console.log('show front')
scope.hideClicked = false;
scope.showClicked = true;
}
scope.frontClicked = function () {
console.log('hide front');
scope.hideClicked = true;
scope.showClicked = false;
}
console.log(scope, element, attrs);
}
and in the template
<div class="tile" ng-class="{'hide-elem': hideClicked,'show-elem': showClicked }">
<span class="front" ng-click="frontClicked()">{{itemData.value}}</span>
<span class="back" ng-click="backClicked();"></span>
</div>
Full code to reproduct is here: https://codepen.io/lkurylo/pen/Laprjx
Both child-span-Elements use absolute positioning, so it seems as if the browser decides that the second element is displayed "on top" of the first. As a result, the click only registers on the back-Element, which happens to be the top-element.
I suggest you display only one element at any given time, e.g. by adding ng-show or ng-if to both elements.
<span class="front" ng-if="showClicked" ng-click="..."></span>
<span class="back" ng-if="hideClicked" ng-click="..."></span>

How to replace a child div on it's existing parent div using angularjs?

I have the following code.
html:
<div ng-controller="Test">
<div ng-click="first()" ng-hide="seconddiv">First
<div ng-click="second()" ng-show="seconddiv">Second</div>
</div>
</div>
js:
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.first = function(){
alert("first clicked");
}
$scope.second = function(){
alert("second clicked");
}
});
On executing the above code:
a). I should see only First by default(I can see one now: First) - it is fine now
b). then, if I click on First, then it should execute it's first() method, then First should be replaced with Second(on UI) - it's not coming
c). then, if I click on Second, then it should execute it's second() method only, (it should not execute any other methods like first() except second() method) - it's not coming
I request you to please help me regarding this that how can we do this? Thanks in advance!
Please note that Html <div> structure should not change, so it should be same.
Created Fiddle .
Go the Angular Way.
You will have just one function, toggle. Which will toggle the value of variable first from true to false and vice versa.
Depending on value of first you will show either div with content as First or that with content as Second.
You will also refactor your HTML a bit as follows
<div ng-controller="Test">
<div ng-if="first" ng-click="toggle()">First</div>
<div ng-if="!first"ng-click="toggle()">Second</div>
</div>
And in your JS you will do
var app = angular.module('app',[]);
app.controller('Test',function($scope){
$scope.first = true;
$scope.toggle = function(){
$scope.first = !$scope.first;
}
});
====
EDIT:
Alternatively, you don't even need the toggle function. Just use ng-click expression.
<div ng-controller="Test">
<div ng-if="first" ng-click="first=!first">First</div>
<div ng-if="!first"ng-click="first=!first">Second</div>
</div>
And in JS
app.controller('Test',function($scope){
$scope.first = true;
});

Use ng-class to display some text

Can I use ng-class to display text in addition to a temporary class on my div?
Here's my code.
HTML:
<button ng-click="setBulkMode()"
<div class="filter-nav-bar" ng-class="{'filter-nav-bar-bulk-mode': bulkMode}">
JS:
$scope.setBulkMode = function() {
if(!$scope.bulkMode) {
$scope.bulkMode = true;
} else {
$scope.bulkMode = false;
}
};
Whenever I'm setting bulkMode to true, on my ng-class I'd like to display some text as well. So something like...
<div class="filter-nav-bar" ng-class="{'filter-nav-bar-bulk-mode': bulkMode 'Bulk Mode On'">
But I'm not quite sure how to do that. Any ideas?
Try the following:
<div class="filter-nav-bar" ng-class="{'filter-nav-bar-bulk-mode': bulkMode">
<span ng-show="bulkMode">Bulk Mode On</span>
And you dont need that function to set, you can do this easily in the view:
<button ng-click="bulkMode = !bulkMode">
Separate it. Create a new div with the ng-if directive to show it conditionally:
<div ng-if="bulkMode">Bulk Mode On</div>
And also, you can better write your function (personally I would rename it to toggleBulkMode):
$scope.setBulkMode = function() {
$scope.bulkMode = !$scope.bulkMode;
};

Showing div in angularjs not working

I want to show a div only when the function happens.
Here is the HTML, but it is always showing, I want it to show only when the function is true
<div ng-controller="controller">
<div ng-show="data.show"> Successfully triggered </div>
<div ng-hide="!(data.hide)"> Error in triggering</div>
</div>
In the controller I have:
if(results.data=='success') {
$scope.data = {
show: false,
hide: true
};
//Here I should display the success message
} else {
//Here I should display the error message
}
So, How can I show the success div in if condition and error div in the else condition.
Note : If possible if the div is shown in slow motion it will be very helpful for me. Like the fade timing in jQuery.
You should only maintain only one flag data.show that is more than sufficient to show hide div.
<div ng-controller="controller">
<div ng-show="data.show"> Successfully triggered </div>
<div ng-hide="data.show"> Error in triggering</div>
</div>
Controller
app.controller('myCtrl', function(){
///other stuff here ..
$scope.myFunction = function(){
if(results.data=='success') {
$scope.data.show = true; //success
} else {
$scope.data.show = false; //error
}
}
//init code here
$scope.data = { show: false }; //this should be outside your show/hide function
})
I would use one div something like the following
<div ng-controller="controller">
<div ng-show="data.show">{{data.message}}</div>
</div>
Get rid of your hide property on data it isn't needed and set your text in the controller on another data property. The bottom line is data.show has to be "truthy" for the div to show up. Honestly, if you are always going to show a div I would get rid of ng-show and just dynamically set the div content in the controller.
here is my example: Example for show div on jsfiddle
<div ng-app>
<div ng-controller="showCtrl">
<div>Show Div:
<button ng-click="set()"></button>
<div ng-show="showDiv"> Successfully triggered </div>
<div ng-hide="showDiv"> Error in triggering</div>
</div>
</div>
</div>
If you want to add fade in and fade out timing, I suggest you to look up angular animate. Documentation and example for angular animate.
wow, there are already so many answers, and they are all correct. Everybody also rightly pointed out that to have a little animation, you can use ngAnimate.
My little jsFiddle is here, just as a fun little exercise.
var app = angular.module('app', ['ngAnimate']);
app.controller('testCtrl', function ($scope) {
$scope.data = {
show:true,
hide: false
};
$scope.go = function(checked) {
$scope.data = {
show:!checked,
hide: checked
};
}
});
https://jsfiddle.net/dshun/j8wgnnm5/13/

How do I move a view around the DOM with angular.js?

How can I move an element to different places in the DOM with angular js?
I have a list of elements like so
<ul id="list" ng-controller="ListController">
<li ng-controller="ItemController"><div>content</div></li>
<li ng-controller="ItemController"><div>content</div></li>
<li ng-controller="ItemController"><div>content</div></li>
<li ng-controller="ItemController">
<div>content</div>
<div id="overlay"></div>
</li>
</ul>
What I'm trying to accomplish is moving the #overlay from place to place within the list without having to have a hidden duplicate in every item that I flag hidden/unhidden.
If this was jquery I could just do something like this:
$("#overlay").appendTo("#list li:first-child");
Is there an equivalent way to do this in angular?
Thanks to your clarifications I can understand that you've got a list of items. You would like to be able to select one item in this list (swipe but potentially other events as well) and then display an additional DOM element (div) for a selected item. If the other item was selected it should be un-selected - this way only one item should have an additional div displayed.
If the above understanding is correct, then you could solve this with the simple ng-repeat and ng-show directives like this:
<ul ng-controller="ListController">
<li ng-repeat="item in items">
<div ng-click="open(item)">{{item.content}}</div>
<div ng-show="isOpen(item)">overlay: tweet, share, pin</div>
</li>
</ul>
where the code in the controller would be (showing a fragment of it only):
$scope.open = function(item){
if ($scope.isOpen(item)){
$scope.opened = undefined;
} else {
$scope.opened = item;
}
};
$scope.isOpen = function(item){
return $scope.opened === item;
};
Here is the complete jsFiddle: http://jsfiddle.net/pkozlowski_opensource/65Cxv/7/
If you are concerned about having too many DOM elements you could achieve the same using ng-switch directive:
<ul ng-controller="ListController">
<li ng-repeat="item in items">
<div ng-click="open(item)">{{item.content}}</div>
<ng-switch on="isOpen(item)">
<div ng-switch-when="true">overlay: tweet, share, pin</div>
</ng-switch>
</li>
</ul>
Here is the jsFiddle: http://jsfiddle.net/pkozlowski_opensource/bBtH3/2/
As an exercise for the reader (me), I wanted to try a custom directive to accomplish this. Here is what I came up with (after many failed attempts):
<ul ng-controller="ListController">
<li ng-repeat="item in items">
<div singleton-overlay>{{item.content}}</div>
</li>
</ul>
A service is required to store the element that currently has the overlay, if any. (I decided against using the controller for this, since I think a 'service + directive' would make for a more reusable component than a 'controller + directive'.)
service('singletonOverlayService', function() {
this.overlayElement = undefined;
})
And the directive:
directive('singletonOverlay', function(singletonOverlayService) {
return {
link: function(scope, element, attrs) {
element.bind('click', moveOrToggleOverlay);
function moveOrToggleOverlay() {
if (singletonOverlayService.overlayElement === element) {
angular.element(element.children()).remove();
singletonOverlayService.overlayElement = undefined;
} else {
if (singletonOverlayService.overlayElement != undefined) {
// this is a bit odd... modifying DOM elsewhere
angular.element(singletonOverlayService.overlayElement.children()).remove();
}
element.append('<div>overlay: tweet, share, pin</div>')
singletonOverlayService.overlayElement = element;
jsFiddle: http://jsfiddle.net/mrajcok/ya4De/
I think the implementation is a bit unconventional, though... the directive not only modifies the DOM associated with its own element, but it may also modify the DOM associated with the element that currently has the overlay.
I tried setting up $watches on scope and having the singleton store and modify scope objects, but I couldn't get the $watches to fire when I changed the scope from inside the moveOrToggleOverlay function.

Categories

Resources