I'm using angularjs with the implementation "Angular Material" (here: https://material.angularjs.org/latest/#/)
I'm using the SideNav component: https://material.angularjs.org/latest/#/demo/material.components.sidenav to open a lateral container on click in a menu link. It's working right now... But when i click the menu item i should change the value of a boolean variable from false to true.. This doesn't happen. I don't know exactly why. In my controller i have this part of code:
$scope.toggleRight = buildToggler('right');
$scope.myBoolean = false;
/**
* Build handler to open/close a SideNav; when animation finishes
* report completion in console
*/
function buildToggler(navID) {
var debounceFn = $mdUtil.debounce(function(){
$mdSidenav(navID)
.toggle()
.then(function () {
$log.debug("toggle " + navID + " is done");
});
},300);
return debounceFn;
};
$scope.close = function () {
$mdSidenav('right').close()
.then(function () {
$log.debug("close RIGHT is done");
});
};
That it's the part to open and close the container. Then in my html
<li>
<a data-ng-click="myBoolean = true;">
Open the container
</a>
</li>
So, if the variable was "false" now should be "true" when the item of the menu is clicked. But still remains false.. What's wrong?
//Just write down the below function i controller
$scope.openContainer = function () {
$scope.myBoolean = true;
}
//and in View change below
<li>
<a data-ng-click="openContainer()">Open the container</a>
</li>
Try changing the variable in this way:
<li>
<a data-ng-click="$parent.myBoolean = true;">
Open the container
</a>
</li>
Use $parent property. I believe the sidenav component has its own scope and the link is inside the sidenav component. So in order to access the variable in your scope you need to go one level upper (in the parent scope)
Related
I am new to programming in Javascript .so please explain me can I use binding here.This menu is inspired by the left side menu found on YouTube. When clicking on the menu label and icon, the main menu appears beneath and the menu icon slides to the right side while the label slides up. To close the menu, the menu icon needs to be clicked again.
var menu = (function() {
function initiate() {
//[].slice.call I used by using call but i want to to by binding and I am not able to do.
[].slice.bind(null, document.querySelectorAll('.menu')).forEach(function(element, i) {
var titleclick = el.querySelector('div.d-striker'),
striker.addEventListener('click', function(event) {
if (!open) {
el.className += ' dr-menu-open';
open = true;
}
}, false);
icon.addEventListener('click', function(event) {
if (open) {
event.stopPropagation();
open = false;
el.className = el.className.replace(/\bdr-menu-open\b/, '');
return false;
}
}, false);
}
initiate();
})();
<div class="side">
<nav class="menu">
<div class="d-striker">
<span class="d-icon dr-icon-menu"></span><a class="dr-label">Account</a>
</div>
<ul>
<li><a class="d-icon dr-icon-user" href="#">icon</a></li>
<li><a class="d-icon dr-icon-cam" href="#">Videos</a></li>
<li><a class="d-icon dr-icon-download" href="#">Downloads</a></li>
<li><a class="d-icon dr-icon-settings" href="#">Settings</a></li>
</ul>
</nav>
</div>
bind() returns a bound function, but you need to call that function to get the array that's needed for forEach. Add parentheses to call the function.
[].slice.bind(null, document.querySelectorAll('.menu'))().forEach(function(element, i) {
^^
I'm totally new to angular and I try to use angular-bootstrap-datetimepicker in my project. My html code is:
<span class="input-group-btn" ng-class="{open: openedDP}">
<button type="button" class="btn btn-default btn-sm" ng-click="open()">
<i class="glyphicon glyphicon-calendar"></i>
</button>
<ul class="dropdown-menu" role="menu">
<datetimepicker ng-model="abc"
on-set-time="close(new, old)">
</datetimepicker>
</ul>
</span>
<input id="abc" ng-model="abc" class="form-control" date-time-input="DD-MM-YYYY HH:mm:SS" />
I wanted to close a calendar when user clicks anywhere outside it. I almost copy-pasted the code from ui.bootstrap. Original one is inside directive and looks like this:
var documentClickBind = function(event) {
if (scope.isOpen && event.target !== element[0]) {
scope.$apply(function() {
scope.isOpen = false;
});
}
};
scope.$watch('isOpen', function(value) {
if (value) {
scope.$broadcast('datepicker.focus');
scope.position = appendToBody ? $position.offset(element) : $position.position(element);
scope.position.top = scope.position.top + element.prop('offsetHeight');
$document.bind('click', documentClickBind);
} else {
$document.unbind('click', documentClickBind);
}
});
My version (inside controller):
var documentClickBind = function (event) {
if ($scope.openedDP) {
$scope.$apply(function () {
$scope.openedDP = false;
});
}
};
$scope.$watch('openedDP', function (value) {
if (value) {
$timeout(function() {
$document.bind('click', documentClickBind);
}, 0, false);
} else {
$document.unbind('click', documentClickBind);
}
});
I removed "element" variable because I don't have it in my controller and it seems to work, but I don't know why. Maybe it works just by chance? Why clicking inside calendar is different than clicking anywhere else? In addition I'd like to avoid creating multiple functions like this when I have multiple datepickers on a page.
The behavior you want is built-in to the bootstrap dropdown, if you have bootstrap already in your project you might consider making use of its dropdown.
If not, you could create a custom directive on the page that broadcasts a 'page-clicked' event when the user clicks on another part of the page, then each controller can listen for that event on their scope and react accordingly.
I'm fairly new to JS and I can't quite figure out how to get this to work. Any help is very much appreciated! So I have a hamburger button that, when clicked, simultaneously toggles the animation of a slide-in panel and hamburger animation by adding a class to the panel and button. I have successfully added a click event to close the panel if user clicks anywhere outside of the panel but I can't get the hamburger button to remove the added classes as well. I'd like the user to have both options (click button or click outside of panel).
HTML:
<ul class="nav nav--right">
<li class="v-button--slide-right" id="toggle-menu">
<button class="mpp-menu-icon mpp-menu-icon--cross toggle-menu">
<span class="toggle"></span>
<span class="menu">menu</span>
</button>
</li>
</ul>
<nav id="menu--slide-right" class="nav menu--slide-right">
<ul class="main-menu">
<li>Home</li>
<li>About</li>
</ul>
</nav><!-- end slide menu -->
JS:
jQuery(document).ready(function($) {
var openSidebar = function() {
$('.menu--slide-right').addClass('is-active');
$('.toggle-menu').addClass('is-active');
$('#toggle-menu').addClass('toggle-close');
}
var closeSidebar = function() {
$('.menu--slide-right').removeClass('is-active');
$('.toggle-menu').removeClass('is-active');
$('#toggle-menu').removeClass('toggle-close');
}
$('.toggle-menu').click(function(event) {
event.stopPropagation();
openSidebar();
});
$(document).click(function(event) {
if (!$(event.target).closest('.menu--slide-right').length) {
closeSidebar();
}
});
});
And here's a JSFIDDLE to demo what I have so far
Very simple fix - add an "open" variable which changes to true when the sidebar opens, and evaluate this variable in your click event handler.
Add the variable:
var open = false;
Add the variable mutators to your open and close functions:
var openSidebar = function(){
$('.menu--slide-right').addClass('is-active');
$('.toggle-menu').addClass('is-active');
$('#toggle-menu').addClass('toggle-close');
open = true; //This is the new part!
}
Then toggle which function to call on button click - I achieve this with a ternary operator:
$('.toggle-menu').click( function(event) {
event.stopPropagation();
var toggle = open ? closeSidebar : openSidebar;
toggle();
});
Check the fiddle here
A quick and dirty way to fix this is to change your openSideBar function to use jQuery's toggleClass method, i.e.:
var openSidebar = function() {
$('.menu--slide-right').toggleClass('is-active');
$('.toggle-menu').toggleClass('is-active');
$('#toggle-menu').toggleClass('toggle-close');
}
This way when a user clicks on the button, it will toggle the class on/off, and you already have the code to turn it off when they click outside of the button.
Check it out here: https://jsfiddle.net/5ssccz2a/2/
jQuery .toggleClass(): http://api.jquery.com/toggleclass/
The simplest and most robust way would be to check if one of your classes are active on the button. So also no extra variables are needed. I would recommend, deciding on one class to control the others.
$('.toggle-menu').click(function(event) {
if ($('.toggle-menu').hasClass('is-active') {
closeSidebar();
}
else {
openSidebar();
}
event.stopPropagation();
});
Test for .is-active class before deciding whether to run closeSidebar() or openSidebar() when .toggleMenu is clicked.
$('.toggle-menu').click( function(event) {
event.stopPropagation();
if( $(this).is('.is-active') ) {
closeSidebar();
} else {
openSidebar();
}
});
DEMO
Or, using the ternary operator:
$('.toggle-menu').click( function(event) {
event.stopPropagation();
$(this).is('.is-active') ? closeSidebar() : openSidebar();
});
DEMO
I'm prototyping a web app dealing with lots of views that are off screen until activated by an element currently on screen. Example:
<div class='current' data-view='home'>
<a href='#' data-target='menu'>View Menu</a>
</div>
<div data-view='menu'>
<a href='#' data-target='home'>Go back home</a>
</div>
Right now I've got the jQuery rigged to find the matching value of "data-target" to "data-view". When it finds the match, it toggles the class "current" between the two views.
Anyways! I'm hoping someone could help me figure out a good way to apply my enter and exit animations to the toggled elements. Here's what I tried:
$('[data-target]').on('click', function () {
var parentView = $(this).parents('[data-view]'),
currentView = $('.current');
function finishedAnimation() {
currentView.one('webkitAnimationEnd oanimationend msAnimationEnd animationend',
function() { currentView.removeClass(); });
};
if (parentView.data('view', 'home')) {
targetView.addClass('moveFromTop');
currentView.addClass('moveToBottom');
finishedAnimation();
}
else if (parentView.data('view', 'menu')) {
targetView.addClass('moveFromBottom');
currentView.addClass('moveToTop');
finishedAnimation();
}
$(this).parents('body').find('[data-view=' + $(this).data('target') + ']').addClass('current');
});
It works on the first click, but on the subsequent click to return home it fails to perform the animation correctly.
I've been digging around and switch cases look like a viable option (?). If anyone has guidance on a better approach it would be much appreciated.
Not exactly sure how your setup works, but I prefer to use an object ( as an interface ) for something like this:
function handleView( view ) {
views = {
home : function(){ /* Do stuff with view here */ },
menu : function(){}
}
views[view]()
}
$('[data-target]').on('click', function (e) {
e.preventDefault()
view = $(this).parent().data('view') /* This should return 'view name' */
handleView( view );
});
Remember that if you're adding a class that has a transition associated with it, you'll need to remove it too.
so targetView.addClass('moveFromTop'); needs targetView.removeClass('moveFromTop'); in order to properly toggle.
I have the following code It takes a <ul> and it drops down the contents when clicked. That works great. The problem was that it would also close other menus of the same type when a child <li> was clicked.
I 'fixed' this problem by using the if clause to determine if the item being clicked was also the item that was currently open, but I want to take it a step further and make it so that if the parent ul is clicked again, it will close the menu. I am having a great deal of misunderstanding as to how to approach this. I attempted to stop the propagation of the children elements, but it yields the same results. Can anyone assist?
wiring (document load)
$(document).ready(function () {
$('[data-role="sidebar-dropdown"]').drawer({
open: 'sidebar-dropdown-open',
css: '.sidebar-dropdown-open'
});
});
html
<ul>
<li class=" dropdown" data-role="sidebar-dropdown">
Link Text
<ul class="sub-menu light sidebar-dropdown-menu">
<li><a class="remote" href="pages/...">Link Text</a></li>
<li><a class="remote" href="pages/...">Link Text</a></li>
<li><a class="remote" href="pages/...">Link Text</a></li>
</ul>
</li>
</ul>
JavaScript
(function ($) {
$.fn.drawer = function (options) {
// Create some defaults, extending them with any options that were provided
var settings = $.extend({
open: 'open',
css: '.open'
}, options);
return this.each(function () {
$(this).on('click', function (e) {
// slide up all open dropdown menus
$(settings.css).not($(this)).each(function () {
$(this).removeClass(settings.open);
// retrieve the appropriate menu item
var $menu = $(this).children(".dropdown-menu, .sidebar-dropdown-menu");
// slide down the one clicked on.
$menu.slideUp('fast');
$menu.removeClass('active');
});
// mark this menu as open
$(this).addClass(settings.open);
// retrieve the appropriate menu item
var $menu = $(this).children(".dropdown-menu, .sidebar-dropdown-menu");
// slide down the one clicked on.
$menu.slideDown(100);
$menu.addClass('active');
e.preventDefault();
e.stopPropagation();
}).on("mouseleave", function () {
$(this).children(".dropdown-menu").hide().delay(300);
});
})
};
})(jQuery);
In jQuery events you can read the node which initiated the event by referencing e.target.
if ($(e.target).is("li")) { // do something only if the clicked element was a li }
Regarding closing elements which are not children, instead of doing a global selector $(selector) you should instead do a selector relative to your initiating dom node. It's a common practice to pass this and stashing it inside your jQuery plugin.
return this.each(function(this)) { var $node = $(this); }
Then all lookups would be done like
$node.find(selector).doStuff()