An area i have some points. By default all disabled to draggable. If user click on edit link the point with 43 position should be draggable. but point still have disable state and watch function not executing..
jsFiddle
HTML
<div ng-app="myapp" ng-controller="MainController">
Make point 43 draggable
<ul class="court">
<li ng-repeat="point in courtPoints" droppable data-location="{{point.location}}">
{{point.location}}
<div class="draggable-point draggable-point-location"
location-point-draggable ng-show="point.marker==true"></div>
</li>
</ul>
</div>
JS
var myapp = angular.module('myapp', []);
myapp.directive('locationPointDraggable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.draggable({
containment: '.court',
cursor: 'move',
cancel: 'a',
revert: 'invalid',
snap: 'true',
stop: function (event, ui) {
}
});
}
};
});
myapp.controller('MainController', ['$scope', function ($scope) {
Array.range = function (start, end) {
var arr = [];
for (var i = start; i < end; i++) {
var point = {};
point.location = i + 1;
point.marker = false;
point.allowDrag = false;
arr[i] = point;
}
return arr;
};
$scope.init = function () {
$scope.courtPoints = Array.range(0, 50);
$scope.courtPoints[42].marker = true; //42 because start from zero
};
$scope.edit = function (id) {
$scope.courtPoints[42].allowDrag = true;
$scope.courtPoints[42].location = '2014';
};
$scope.init();
}]);
angular.bootstrap(document, ['myapp']);
I think you want to enable the dragging element when user click on the "Make point 43 draggable".
On your fiddle you forgot to add jQueryUI so the draggable function is not working and return undefined.
And one more thing, your draggable function need to specify which element to disable dragging on the cancel attribute, in this case you specify a tag "a" which is not correct because you want to disable the dragging on the yellow circle which is a "div" inside "li" tag. I have used:
ng-class
which add a "disable" class when your allowDrag attribute object is false. You can change the draggable function as follow:
myapp.directive('locationPointDraggable', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
element.draggable({
containment: '.court',
cursor: 'move',
cancel: '.disable',
revert: 'invalid',
snap: 'true',
stop: function (event, ui) {
}
});
}
};
});
And change your markup html like this :
<div class="draggable-point draggable-point-location"
location-point-draggable
ng-show="point.marker==true"
ng-class='{"disable" : !point.allowDrag, "":point.allowDrag}'
</div>
Button 43 should be dragging disabled initially.
And now when you click on
Make point 43 draggable
Button 43 should be dragging enabled.
Working fiddle : http://jsfiddle.net/themyth92/gd2kzps2/
Related
I'm trying to toggle a class by setting a Boolean value with ng-class. Now while using a custom directive while clicking outside of my focusing element needs to change the Boolean to false.
app.factory('collapsed', function($rootScope){
var scope = $rootScope.$new(true);
scope.isCollapsed = true
return scope;
})
app.controller('optSideNav', optSideNav);
function optSideNav(collapsed) {
var self = this;
this.isCollapsed = collapsed.isCollapsed;
}
app.directive('offFocusing', ['$document', 'collapsed', function ($document, collapsed) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
console.log(element)
function elementClick(e) {
e.stopPropagation();
scope.isCollapsed = collapsed.isCollapsed;
}
element.on('click', elementClick);
// remove event handlers when directive is destroyed
scope.$on('$destroy', function () {
element.off('click', elementClick);
});
}
};
}]);
<!--controller area -->
<navng-class="sideNav.isCollapsed ? 'opt-sideNav' : 'opt-sideNavXl'" ng-controller="optSideNav as sideNav" ng-model="sideNav.isCollapsed">
<a ng-click="sideNav.isCollapsed = !sideNav.isCollapsed""><i class="material-icons md-16">menu</i></a>
</nav>
<!--directive area-->
<section class="opt-appArea" flex layout="column" off-focusing>
</section>
How do I asynchronously obtain the value changes while click element to controller?
I'm new to AngularJs and learning now, in my current assignment I need to achieve multiple things on ng-click.
To hide and show some DOM elements based on the ng-click
Change the background of the element where the ng-click is applied on, I'm trying to acheive this using a directive.
Mark-up:
<div class="catFilter f6" ng-click="showSubCat = !showSubCat;toggleDropDown()">
Choose A Genre
</div>
<div class="inactive" ng-show="showSubCat" ng-click="hideSubCat = !hideSubCat" ng-hide="!hideSubCat">
</div>
<div class="cat-drop-menu-list" ng-show="showSubCat" ng-hide="!hideSubCat">
</div>
angular directive
retailApp.directive('toggleDropDown', function() {
return function(scope, element, attrs) {
$scope.clickingCallback = function() {
element.css({'background':'url("../images/down-arrow.png") no-repeat 225px 12px;'});
};
element.bind('click', $scope.clickingCallback);
}
});
Issues:
I'm not able to see the directive being applied, i.e., when I click on choose a genre, it is hiding and showing the other two divs, but not changing the back ground.
You can do this a couple ways, with bindings or directives:
http://jsfiddle.net/abjeex75/
var app = angular.module('app', []);
app.controller('AppCtrl', function ($scope) {
$scope.show_sub_cat = false;
$scope.show = function () {
$scope.show_sub_cat = true;
}
$scope.hide = function () {
$scope.show_sub_cat = false;
}
});
app.directive('toggleBg', function () {
var directive = {
restrict: 'A',
link: link
}
return directive;
function link(scope, element, attr) {
element.on('click', function () {
element.toggleClass('red');
});
}
});
I am trying to implement a dropdown mega-menu using Angular, where if the user clicks on Link 1, then the content for Link 1 should appear. My directives are as followed:
mobile-menu which acts as a controller and keeping track of the links and menu items states
menu-link, the actual link that user clicks on to open/close the menu items
menu-item, the menu item that should show/hide based on the scope.test value
Here is my AngularJS code:
angular.module("myApp", [])
.controller("testCtrl", function ($scope) {})
.directive("mobileMenu", function () {
return {
controller: function ($scope) {
this.menuLinks = [];
this.menuItems = [];
this.addMenuLink = function (l) {
this.menuLinks.push(l);
};
this.addMenuItem = function (m) {
this.menuItems.push(m);
};
// Function to close all other menu items if they are open.
// This is because only one menu item can be active at a time
this.closeOthers = function (selectedMenuLink) {
angular.forEach(this.menuLinks, function (l) {
if (l !== selectedMenuLink) {
l.selected = false;
}
});
angular.forEach(this.menuItems, function (m) {
if (selectedMenuLink.target == m.menuId) {
m.test = true;
} else {
m.test = false;
}
});
};
}
};
}).directive("menuLink", function () {
return {
require: "^mobileMenu",
scope: {},
link: function(scope, element, attrs, menuController) {
scope.selected = false;
menuController.addMenuLink(scope);
scope.$watch('selected', function(newValue, oldValue) {
if (oldValue === newValue) {return};
if (newValue) {
scope.target = angular.element(element[0].children[0]).attr("data-menu");
menuController.closeOthers(scope);
}
});
}
};
}).directive("menuItem", function () {
return {
require: "^mobileMenu",
scope: true,
link: function (scope, element, attrs, menuController) {
scope.test = false;
scope.menuId = attrs.id;
menuController.addMenuItem(scope);
scope.$watch('test', watchLink);
scope.$watch(attrs.collapse, watchLink);
scope.$watch(function () {
return scope.test;
}, watchLink);
var watchLink = function (newValue, oldValue) {
// Initializing for the first time, do nothing
if (newValue === oldValue) return;
// If the collapse attribute has a true value, collapse this element
if (newValue) {
collapse();
} else {
expand();
}
};
// Helper function to collapse the element
var collapse = function () {
element.css({
height: "0px"
});
};
// Helper function to show the element
var expand = function () {
element.css({
height: "200px"
});
};
}
};
});
And here is my HTML code:
<div ng-app="myApp" ng-controller="testCtrl">
<div mobile-menu>
<ul>
<li menu-link>
Link 1
</li>
<li menu-link>
Link 2
</li>
</ul>
<div id="menu0" ng-class="{'expanded' : test, 'collapsed' : !test}" menu-item collapse="!test">
<p class="text">First Menu</p>
</div>
<div id="menu1" ng-class="{'expanded' : test, 'collapsed' : !test}" menu-item collapse="!test">
<p class="promo-text">Second Menu</p>
</div>
</div>
I have an issue where if menu-link #1 is clicked, the corresponding menu-item #1's scope.test value should be updated and its' scope watch should be triggered, but it does not. If the scope watch triggered the watchLink function, then I would expect menu-item #1 would have a height of 200px.
I have also attached a jsfiddle example:
http://jsfiddle.net/EmwBP/28/
If you look at the browser console tool, the corresponding menu-item ng-class is always updated based on its scope.test value. However, even with my 3 different scope watchers set up, none of them were triggered. I am also using the ng-class directive just to show that the scope.test value does get updated and will be removed in the final implementation.
Normally, I would have put the menu-item directives as a child of menu-links, but I have a requirement where I have to put the menu-items as it is right now to achieve the slide-down effect of pushing elements below it down.
Many thanks in advance for your advices and assistance
You create a new isolated scope in menuLink by using scope: {}. So whatever scope variables you set inside that scope (like selected) are only available within that scope, and will not propagate to sibling or parent scopes.
What you need to do is de-isolate the menuLink scope by using scope: true.
That is not the problem. The problem is that watchLink is used before you define it. Fix where watchLink is triggered: http://jsfiddle.net/EmwBP/31/
Anyone have a simple directive to automatically show a Bootstrap modal? In Bootstrap 3 they took away the ability to automatically show the modal so I can't use a angular ng-if show block. Any help would be great.
Updated for angular 1.2 & Bootstrap 3.1.1: http://embed.plnkr.co/WJBp7A6M3RB1MLERDXSS/
I extended Ender2050's answer so the directive does not have an isolated scope. This means the modal contents can contain references to scope objects. Also reuse the directive attribute so only one attribute is needed.
app.directive("modalShow", function ($parse) {
return {
restrict: "A",
link: function (scope, element, attrs) {
//Hide or show the modal
scope.showModal = function (visible, elem) {
if (!elem)
elem = element;
if (visible)
$(elem).modal("show");
else
$(elem).modal("hide");
}
//Watch for changes to the modal-visible attribute
scope.$watch(attrs.modalShow, function (newValue, oldValue) {
scope.showModal(newValue, attrs.$$element);
});
//Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
$(element).bind("hide.bs.modal", function () {
$parse(attrs.modalShow).assign(scope, false);
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
}
};
});
Usage:
<div modal-show="showDialog" class="modal fade"> ...bootstrap modal... </div>
Here's an Angular directive that will hide and show a Bootstrap modal.
app.directive("modalShow", function () {
return {
restrict: "A",
scope: {
modalVisible: "="
},
link: function (scope, element, attrs) {
//Hide or show the modal
scope.showModal = function (visible) {
if (visible)
{
element.modal("show");
}
else
{
element.modal("hide");
}
}
//Check to see if the modal-visible attribute exists
if (!attrs.modalVisible)
{
//The attribute isn't defined, show the modal by default
scope.showModal(true);
}
else
{
//Watch for changes to the modal-visible attribute
scope.$watch("modalVisible", function (newValue, oldValue) {
scope.showModal(newValue);
});
//Update the visible value when the dialog is closed through UI actions (Ok, cancel, etc.)
element.bind("hide.bs.modal", function () {
scope.modalVisible = false;
if (!scope.$$phase && !scope.$root.$$phase)
scope.$apply();
});
}
}
};
});
Usage Example #1 - this assumes you want to show the modal - you could add ng-if as a condition
<div modal-show class="modal fade"> ...bootstrap modal... </div>
Usage Example #2 - this uses an Angular expression in the modal-visible attribute
<div modal-show modal-visible="showDialog" class="modal fade"> ...bootstrap modal... </div>
Another Example - to demo the controller interaction, you could add something like this to your controller and it will show the modal after 2 seconds and then hide it after 5 seconds.
$scope.showDialog = false;
$timeout(function () { $scope.showDialog = true; }, 2000)
$timeout(function () { $scope.showDialog = false; }, 5000)
I'm anxious to see what other solutions people come up with. Cheers!
I am using bs-popover to display my contents on click(as a menu) in angularjs. But I need to hide this popover-menu when I click somewhere in the browser window. I want it to be dismissed on that type of event. How can I do that?
You need to write directive for this.
yourApp.directive('bndocumentclick',
function($document,$rootScope,$timeout) {
return {
restrict: 'EA',
link : function(scope, element, attrs) {
$document.on("click", function(ev) {
// Do stuff here to remove your popover.
}
}
}
});
HTML
<body bndocumentclick>
And
<div bs-popover ng-click="$event.stopPropagation()">
You need to use because you would not like to close your popover whenever user clicks inside popover.
The solution provied by #Jay Shukla doesn't work.
The "$event.stopPropagation()" on the element that triggers the popover doesn't stops it from closing when you make a click inside the popover.. if you have some interaction inside your popover this will be a problem.
This works:
angular.module('yourApp')
.directive('closePopovers', function ($document, $rootScope, $timeout) {
return {
restrict: 'EA',
link: function (scope, element, attrs) {
$document.on('click', function (ev) {
var targetElem = angular.element(ev.target);
if (targetElem.data('toggle') !== 'popover'
&& targetElem.parents('[data-toggle="popover"]').length === 0
&& targetElem.parents('.popover').length === 0) {
$('.popover').each(function () {
var $this = $(this);
var scope = $this.scope();
scope.$apply(function () {
scope.$hide();
});
}
);
}
});
}
};
});
On your body:
On your element that triggers the popover:
<button data-toggle="popover" [other data elements here] bs-popover>Toggle popover</button>