patternjavascriptMinor
Angular directive to toggle sidebar visibility based on window width
Viewed 0 times
directivesidebarangularvisibilitywidthbasedwindowtoggle
Problem
I changed the normal way of using Angular. I'm using my controllers just to talk to my API routes and am using directives to manipulate the data and DOM as well.
I am using the object literal pattern where I have my INIT method that initializes global variables (object) and then calls other methods, bind clicks methods, etc. So, the logic is all the directives.
I'm finding it very confusing and would like the opinion of someone better.
```
'use strict';
var eventSidebarDirective = {
/**
* Initialize sidebar directive and return the link
* calling all nested methods.
*
*/
init: function() {
return {
link: function(scope) {
scope.$watch('events', function() {
if (scope.events === undefined) {
return;
}
/**
* Every time the user access the event page, this methods
* will be called.
*
*/
EventSidebar.init();
});
},
restrict: 'M'
};
}
};
var EventSidebar = {
init: function() {
this.element = $('[data-event-sidebar]');
this.indicator = $('[data-event-sidebar-to]');
/**
* To manipulate the element, bind a click in the indicator.
*
*/
this.indicator.bind('click', this._toggle.bind(this));
},
_toggle: function(e) {
var state = $(e.currentTarget).data('event-sidebar-to');
this.element
.css({
/**
* If the window width is less than 768px, i just want toggle
* between display block and none.
*
*/
display: 768 >= $(window).width()
? (state
? 'block'
: 'none')
: false
I am using the object literal pattern where I have my INIT method that initializes global variables (object) and then calls other methods, bind clicks methods, etc. So, the logic is all the directives.
I'm finding it very confusing and would like the opinion of someone better.
```
'use strict';
var eventSidebarDirective = {
/**
* Initialize sidebar directive and return the link
* calling all nested methods.
*
*/
init: function() {
return {
link: function(scope) {
scope.$watch('events', function() {
if (scope.events === undefined) {
return;
}
/**
* Every time the user access the event page, this methods
* will be called.
*
*/
EventSidebar.init();
});
},
restrict: 'M'
};
}
};
var EventSidebar = {
init: function() {
this.element = $('[data-event-sidebar]');
this.indicator = $('[data-event-sidebar-to]');
/**
* To manipulate the element, bind a click in the indicator.
*
*/
this.indicator.bind('click', this._toggle.bind(this));
},
_toggle: function(e) {
var state = $(e.currentTarget).data('event-sidebar-to');
this.element
.css({
/**
* If the window width is less than 768px, i just want toggle
* between display block and none.
*
*/
display: 768 >= $(window).width()
? (state
? 'block'
: 'none')
: false
Solution
Yes, you're right. Your code is very hard to read.
There are some points that could be improved in my code:
Please have a look at the demo below or in this jsfiddle.
- I think you don't need that
initstuff. Just remove it and add initialization to the controller.
- You don't need jQuery for your directive. This is possible with Angular JS / pure Js. Use
ng-showorng-iffor showing hiding your sidebar and useng-classto add your class conditionally depending on a variable from your controller to do things differently for large screens.
- Animation could be done with
ngAnimateandanimate.css.
There are some points that could be improved in my code:
- Add options so it's better reusable.
- Add default options for example start
visible = false. withangular.module('adminApp').constants(...)then you canangular.extend(...)these in the controller of your directive.
- Add an isolated scope for the directive so it can't modify the scope of your app. Somthing like
scope: {}would be OK or{scope: { options: '@' } }for the sidebar options.
- Remove
restrict: Mbecause it's not recommended to use directives as comments (see angular docs).
Please have a look at the demo below or in this jsfiddle.
function EventSidebarDirective($window) {
var directive = {
restrict: 'EAM',
templateUrl: 'components/sidebar/template.html',
controllerAs: 'ctrl',
controller: function ($scope) {
var self = this, // self needed because toggle is not bound to this ctrl.
screenWidth;
angular.extend(this, {
visible: false,
toggle: function () {
screenWidth = $window.innerWidth; //$(window).width();
self.visible = !self.visible; // toggle visibility
self.largeScreen = ( screenWidth >= 768 );
}
});
},
link: function (scope, element, attr, ctrl) {
}
};
return directive;
}
EventSidebarDirective.$inject = ['$window']; // only need with-out ng-annotate for minification
angular.module('adminApp', ['ngAnimate'])
.directive('eventSidebar', EventSidebarDirective);
.sidebar-content {
width: 200px;
height: 200px;
background: lightgray;
}
.sidebar-content-animation.ng-hide-remove {
-webkit-animation: fadeInLeft 1s;
-moz-animation: fadeInLeft 1s;
-ms-animation: fadeInLeft 1s;
-o-animation: fadeInLeft 1s;
animation: fadeInLeft 1s;
}
.sidebar-content-animation.ng-hide-add {
-webkit-animation: fadeOutUp 1s;
-moz-animation: fadeOutUp 1s;
-ms-animation: fadeOutUp 1s;
-o-animation: fadeOutUp 1s;
animation: fadeOutUp 1s;
}
I'm a sidebar
toggle sidebar
Context
StackExchange Code Review Q#101423, answer score: 3
Revisions (0)
No revisions yet.