This post looks like duplicate, but I think is not. Now you can click Show box and show red box, if you want close this box, click outside.
Question: How close this red box on click again Show box text except click outside. And how change css style after click e.g. change font-size Show box after click
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer',function ($scope){
$scope.openLogin = function(){
$scope.userLogin = true;
};
$scope.hideLoginContainer = function(){
$scope.userLogin = false;
};
});
body {
position:relative;
}
.loginBox {
z-index:10;
background:red;
width:100px;
height:80px;
padding:10px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="userLogin" style="display:none;">
</div>
</body>
To be able to hide the box on click on it, use $scope.userLogin = !$scope.userLogin condition.
To change it's css style, e.g. font-size, use ng-class. If userLogin variable is true, it will add fontSize class into it, changing it's font-size.
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document) {
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer', function($scope) {
$scope.openLogin = function() {
$scope.userLogin = !$scope.userLogin;
};
$scope.hideLoginContainer = function() {
$scope.userLogin = false;
};
});
body {
position: relative;
}
.loginBox {
z-index: 10;
background: red;
width: 100px;
height: 80px;
padding: 10px;
position: absolute;
}
.fontSize {
font-size: 30px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="userLogin" style="display:none;">
</div>
</body>
instead of using multiple $scope for achieve something like this you can use a single $scope variable, take look at code snippet.
var myApplication = angular.module('myApp', []);
myApplication.directive('hideLogin', function($document){
return {
restrict: 'A',
link: function(scope, elem, attr, ctrl) {
elem.bind('click', function(e) {
e.stopPropagation();
});
$document.bind('click', function() {
scope.$apply(attr.hideLogin);
})
}
}
});
myApplication.controller('hideContainer',function ($scope){
$scope.userLogin = true;
$scope.hideLoginContainer = function(){
$scope.userLogin = true;
};
});
body
{
position:relative;
}
.loginBox
{
z-index:10;
background:red;
width:100px;
height:80px;
padding:10px;
position:absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
<body ng-app="myApp" ng-controller="hideContainer">
Show box
<div hide-login="hideLoginContainer()" class="loginBox" ng-show="!userLogin" style="display:none;">
</div>
</body>
You could rename openLogin() to toggleLogin() and change the function accordingly to
$scope.toggleLogin = function(){
$scope.userLogin != $scope.userLogin;
};
That will toggle the box when you click on the link.
For the CSS part, use ng-class to conditionaly sign a class to the element if userLogin ==true
<div ng-class="{'myConditionalClass':userLogin }"></div>
Related
I am trying to create my own directive to highlight selected menu (I know this can be done with ui-sref and ui-sref-active but I need to expand my directive a bit more later on).
I can't get the element to trigger the directive. I want to be able to change a colour of a selected menu but it doesn't even trigger it to start with. I don't get what I'm doing wrong...
angular.module('app', ['ui.router'])
.config(function($stateProvider) {
$stateProvider
.state('home', {
template: '<h2>HOME</h2>'
})
.state('about', {
template: '<h2>ABOUT</h2>'
})
.state('contact', {
template: '<h2>CONTACT</h2>'
});
})
.directive('isMenuActive', ['$state', function($state) {
return {
restrict: 'A',
scope: {
matches: '=isMenuActive'
},
link: function(scope, element, attrs) {
console.log('trigger directive');
for (var i in scope.matches) {
var match = scope.matches[i];
if ($state.current.name.includes(match)) {
console.log('element', element);
element.addClass('active');
break;
}
}
}
}
}])
.controller('mainCtrl', function($state) {
var vm = this;
vm.menus = [
{
name: 'Home',
route: 'home',
matches: ['home', 'some-other-route']
},
{
name: 'About',
route: 'about',
matches: ['about', 'other-route']
},
{
name: 'Contact',
route: 'contact',
matches: ['contact', 'another-route']
}
];
vm.go = function(route) {
$state.go(route);
}
})
ul {
list-style-type: none;
}
ul li {
display: inline-block;
margin-right: 20px;
cursor: pointer;
font-weight: bold;
}
ul li:hover {
opacity: 0.7;
}
.active a {
color: red;
}
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.5/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.22/angular-ui-router.js"></script>
</head>
<body>
<div ng-controller="mainCtrl as vm">
<ul>
<li ng-repeat="menu in vm.menus" ng-click="vm.go(menu.route)" is-menu-active="menu.matches">
<a>{{menu.name}}</a>
</li>
</ul>
</div>
<div ui-view></div>
</body>
</html>
The javascript onDrop event is not executing when an object is dropped into a drop zone. I've tried re-writing this in at least half a dozen ways with no luck and no error message either. I was looking around for reasons that would prevent the ondrop event from executing and found:
HTML5/Canvas onDrop event isn't firing?
and
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#droptargets
To the best of my knowledge, I've accomplished all three requirements to trigger an ondrop event. I implemented both the ondragenter and ondragover events which both contain event.preventDefault(); and return false;. I also have event.preventDefault(); in the ondrop event.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.lists = [{name: "A", list: ["A Object 1", "A Object 2", "A Object 3"]},
{name: "B", list: ["B Object 1", "B Object 2", "B Object 3"]}];
$scope.drag_index = null;
$scope.drag_obj = null;
});
var dragging = false;
function toggle_dz() {
$(".drop-it").toggle();
}
function get_gbls(cs) {
while (cs.$parent) {
cs = cs.$parent;
}
return cs;
}
app.directive('zoneIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('dragenter',function(event){
event.preventDefault();
console.log("Drag Enter!");
return false;
});
$(element).on('dragover',function(event){
event.preventDefault();
console.log("Drag Over!");
return false;
});
}
};
});
app.directive('dragIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('drag',function(event){
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = scope.$index;
get_gbls(scope).drag_obj = scope.obj;
if (!dragging) {
toggle_dz();
dragging = true;
}
});
$(element).on('drop',function(event){
event.preventDefault();
alert("DROPPED!");
});
$(element).on('dragend',function(event){
toggle_dz();
dragging = false;
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = null;
get_gbls(scope).drag_obj = null;
get_gbls(scope).$apply();
});
}
};
});
.zone-it {
height: 150px;
width: 90%;
background-color: #1B6269;
border: 10px dashed #4D3A44;
border-radius: 10px;
margin: 10px 5%;
padding: 15px;
font-size: 100px;
color: #4D3A44;
text-shadow: 0 0 10px black;
}
.zone-it span {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container-fluid" ng-app="myApp" ng-controller="myCtrl">
<h2>Angular Drag n Drop</h2>
<div class="col-xs-6" ng-repeat="list in lists">
<h3>{{list.name}}</h3>
<hr>
<div class="col-xs-12 drop-it zone-it" zone-it style="display: none;"><span class="text-center glyphicon glyphicon-download"></span></div>
<div class="drop-it container-it">
<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="obj in list.list">
<div class="thumbnail drag-it" draggable="true" drag-it style="cursor:pointer">
<div class="caption text-center">{{obj}}</div>
</div>
</div>
</div>
</div>
</div>
Here is a fiddle of my code: https://jsfiddle.net/Ashkeelun/2uLwd077/1/
So, I figured it out. The ondrop event belongs with the drop zone not the item being dragged.
https://jsfiddle.net/Ashkeelun/2uLwd077/4/
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.lists = [{name: "A", list: ["A Object 1", "A Object 2", "A Object 3"]},
{name: "B", list: ["B Object 1", "B Object 2", "B Object 3"]}];
$scope.drag_index = null;
$scope.drag_obj = null;
});
var dragging = false;
function toggle_dz() {
$(".drop-it").toggle();
}
function get_gbls(cs) {
while (cs.$parent) {
cs = cs.$parent;
}
return cs;
}
app.directive('zoneIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('dragenter',function(event){
event.preventDefault();
console.log("Drag Enter!");
return false;
});
$(element).on('dragover',function(event){
event.preventDefault();
console.log("Drag Over!");
return false;
});
$(element).on('drop',function(event){
event.preventDefault();
alert("DROPPED!");
});
}
};
});
app.directive('dragIt', function(){
return {
restrict: 'A',
link: function(scope, element, attrs){
$(element).on('drag',function(event){
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = scope.$index;
get_gbls(scope).drag_obj = scope.obj;
if (!dragging) {
toggle_dz();
dragging = true;
}
});
$(element).on('dragend',function(event){
toggle_dz();
dragging = false;
var scope = angular.element(event.target).scope();
get_gbls(scope).drag_index = null;
get_gbls(scope).drag_obj = null;
get_gbls(scope).$apply();
});
}
};
});
.zone-it {
height: 150px;
width: 90%;
background-color: #1B6269;
border: 10px dashed #4D3A44;
border-radius: 10px;
margin: 10px 5%;
padding: 15px;
font-size: 100px;
color: #4D3A44;
text-shadow: 0 0 10px black;
}
.zone-it span {
display: block;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<div class="container-fluid" ng-app="myApp" ng-controller="myCtrl">
<h2>Angular Drag n Drop</h2>
<div class="col-xs-6" ng-repeat="list in lists">
<h3>{{list.name}}</h3>
<hr>
<div class="col-xs-12 drop-it zone-it" zone-it style="display: none;"><span class="text-center glyphicon glyphicon-download"></span></div>
<div class="drop-it container-it">
<div class="col-sm-6 col-md-4 col-lg-3" ng-repeat="obj in list.list">
<div class="thumbnail drag-it" draggable="true" drag-it style="cursor:pointer">
<div class="caption text-center">{{obj}}</div>
</div>
</div>
</div>
</div>
I created a function validateCode() and when a user clicks on the button validateCode() will trigger.
I want to change the height of the <div class="loginForm"> </div> when the button clicks.
I was trying : http://jsfiddle.net/Lvc0u55v/10358/
Here is a solution using ngClass:
angular
.module('LoginForm', [])
.controller('mainController', [function() {
var self = this;
self.validateCode = function() {
self.setLoginFormModified = true;
};
}]);
.loginForm {
height:140px;
width:150px;
background-color:blue;
}
.loginFormModified {
height: 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<section
ng-app="LoginForm"
ng-controller="mainController as ctrl"
ng-class="{'loginForm': true, 'loginFormModified': ctrl.setLoginFormModified}">
<button ng-click="ctrl.validateCode()">
Click me
</button>
</section>
This is another method you can take into consider too.
This is suitable for simple style changing. It is suggested to create function to modified multiple styles, if you have more complicated cases.
.loginForm {
height: 140px;
width: 150px;
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<section class="loginForm" ng-app="LoginForm"
ng-controller="mainController" ng-style="modified&&{'height':'500px'}">
<button ng-click="modified=true">
Click me
</button>
</section>
<script>
var app = angular.module('LoginForm', []);
app.controller('mainController',[function(){}]);
</script>
define two style properties as follow :
<style>
.loginFormInitialStyle{
height:140px;
width:150px;
background-color:blue;
}
.loginFormChangeStyle{
height:500px;
width:150px;
background-color:blue;
}
</style>
then use ng-class instead of class as follow
<div ng-class="loginForm"></div>
then define $scope.loginForm object with two properties loginFormInitialStyle and loginFormChangeStyle with default values.
$scope.loginForm = {"loginFormInitialStyle":true, loginFormChangeStyle:false}
then in your on-click function just change the values of loginFormObject
$scope.onClick = function(){
$scope.loginForm = {"loginFormInitialStyle":false, loginFormChangeStyle:true}
}
I'm using a template to create a popup menu that will show alerts if there is a new one and it's working till now. But i wanted to add manual alert, that's why i thought to add an input text but Oupss, i can't write on the input field and i don't even know why.The input field is sort of Disabled!!!
My directive is like so :
$scope.tb = { x: 0, y: 0 };
module.directive('myDraggable', function ($document, $interval) {
return {
restrict: 'EA',
replace: true,
//scope : true,
scope: { menu: '=drSrc'},
link: function (scope, element, attr) {
var startX = 0, startY = 0, x = scope.menu.x || 0, y = scope.menu.y || 0, positionX = [], positionY = [], time = [], width, height, moveInterval;
element.draggable({
position: 'relative',
cursor: 'pointer',
top: y + 'px',
left: x + 'px'
});
element.on('mousedown', function (event) {
// Prevent default dragging of selected content
event.preventDefault();
startX = event.pageX - x;
startY = event.pageY - y;
$document.on('mousemove', mousemove);
$document.on('mouseup', mouseup);
$interval.cancel(moveInterval);
});
function mousemove(event) {
y = event.pageY - startY;
x = event.pageX - startX;
//calculate the borders of the document
width = $(document).width() - 350;
height = $(document).height() - 150;
positionX.push(x);
positionY.push(y);
time.push(Date.now());
}
}
}
});
I tried to make scope true but i faced 2 problems, :
I can't move my popup anymore (yes my popup menu is Draggable)
And Also the input text does not show my text i'm typing.
Here's my cache template :
$templateCache.put('control.tpl.html', '<div class="container" my-draggable dr-src="tb"><div><div class="col-sm-1 col-md-1 sidebar"><div class="list-group" ><span href="#" class="list-group-item active" >Manage<input type="text" class="pull-right" placeholder="Type..." /></span><div ng-repeat="Alert in Alerts"><a href="#" ng-click="showLocation(Alert.id)" class="list-group-item" >Alert {{Alert.id}}</span><img src="../images/alert_icon_manage.png" class="pull-right"/> </a></div><span href="#" class="list-group-item active"></span></div></div></div></div>');
I'm new with AngularJS and Directive and I don't know how to solve this but I think it's a problem with Scopes!!
Thank you.
UPDATE :
If I delete scope:{menu:"=drSrc"} That work and i can type what i want but the problem is that my element is no more draggable.
I think it's sth related to scopes. can anyone help please?
scope: true indicates that your directive should inherit its parent's scope, but scope: {menu: '=drSrc'} creates an isolated scope, which remove your template's access to Alerts. When you remove scope: {menu: '=drSrc'}, menu no longer exists, so scope.menu.x fails and your element is no longer draggable.
The simplest fix is to use scope: true and reference scope.drSrc.x, etc. instead of scope.menu.x. With scope: true, you get access to the parent's scope, including drSrc and the Alerts data your template is using.
These writeups are useful in understanding directives and scopes:
Angular's directive docs
Understanding Scopes
What is the difference between '#' and '=' in directive scope
I'm currently working on a project that depends heavily upon Modal Dialogs. Each with their own purpose and dynamic content.
Here's the system I have been working with:
index.html
<!doctype html>
<html ng-app="myApp" ng-controller="MainCtrl">
<head>
<title>Dialogs</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<button ng-click="openDialog()">Open Dialog</button>
<modal-dialog show="showMe" dialog-controller="WelcomeDialogCtrl" context="welcome"></modal-dialog>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js
var app = angular.module('myApp', []);
// The main controller, which will handle index.html
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.showMe = false;
$scope.openDialog = function(){
$scope.showMe = true; // Show the 'welcome' dialog
};
}]);
// The modal dialog directive
app.directive('modalDialog', [function() {
return {
controller: '#', // Bind a controller
name: 'dialogController', // Bind the controller to this attribute name
restrict: 'E',
scope: {
show: '='
},
link: function(scope, element, attrs) {
// Close this dialog (actually ng-hides it)
scope.closeDialog = function() {
scope.show = false;
};
},
templateUrl: function(element, attrs){
// I prefer to load my dialog templates from a separate folder to keep my project tidy
return 'dialogs/' + attrs.context + '.html';
}
};
}]);
// The 'welcome' dialog has its own controller with its own scope
app.controller('WelcomeDialogCtrl', ['$scope', function($scope){
// This can be called by the template that resides within the directive
$scope.exampleFunction = function(text){
console.log('Example function says: ' + text);
};
}]);
welcome.html
<div class="dialog" ng-show="show">
<div class="dialog-overlay"></div>
<div class="dialog-box">
Welcome, be sure to check out this blazin' dialog.
<button ng-click="exampleFunction('Hi!')">Say Hi!</button>
<button ng-click="closeDialog()">Close</button>
</div>
</div>
app.css
body{
background: #eee;
margin: 80px;
}
/*
* Just some fancy schmuck
*/
button{
border-radius: 5px;
background: #272;
color: #fff;
padding: 5px 12px;
border: 0;
}
/*
* The grey, transparent curtain.
*/
.dialog-overlay {
width: 100%;
height: 100%;
position: absolute;
background: #111;
opacity: 0.2;
top: 0;
left: 0;
z-index: 100;
}
/*
* The dialog itself. Horribly centered.
*/
.dialog-box{
background: #fff;
border-radius: 5px;
padding: 10px 20px;
position: absolute;
width: 600px;
height: 300px;
top: 50%;
left: 50%;
margin-left: -300px;
z-index: 110;
}
I also made a Plunker with the same code.
Please view my JSFiddle
I have a fairly wonkey interaction that on a div mouseenter/mouseleave toggles a input checkbox on/off. If said checkbox is set true, it then sets a focus of an adjacent input text field.
I would like to isolate this interaction into a directive that will allow me to duplicate without conflict.
i've color coated the boxes for reference
<body ng-app="ngApp" ng-controller="MainCtrl">
<div class="row">
<div class="span2 box red" leave-edit="uncheckInputBox(false)" enter-edit="checkInputBox(true)">hover</div>
<span class='span8'>
<p>red</p>
<input type="checkbox" ng-model="isChecked">
<input xng-focus='isChecked' ng-model="editingInput">
{{isChecked}}
{{editingInput}}
</span>
</div>
<div class="row">
<div class="span2 box blue" leave-edit="uncheckInputBox(false)" enter-edit="checkInputBox(true)">hover</div>
<span class='span8'>
<p>blue</p>
<input type="checkbox" ng-model="isChecked">
<input xng-focus='isChecked' ng-model="editingInput">
{{isChecked}}
{{editingInput}}
</span>
</div>
</div>
js
var app = angular.module('ngApp', [])
app.controller('MainCtrl', ['$scope', function ($scope) {
'use strict';
$scope.isChecked = false;
$scope.$watch('isChecked', function(newV){
newV && $('#name').focus();
},true);
$scope.checkInputBox = function(val) {
$scope.isChecked = val;
};
$scope.uncheckInputBox = function(val) {
$scope.isChecked = val;
};
}]);
app.directive('xngFocus', function() {
return {
link: function(scope, element, attrs) {
scope.$watch(attrs.xngFocus,
function (newValue) {
newValue && element.focus();
},true);
}
};
});
app.directive('leaveEdit', function(){
return function(scope, element, attrs) {
element.bind('mouseleave', function() {
scope.$apply(attrs.leaveEdit);
});
};
});
app.directive('enterEdit', function(){
return function(scope, element, attrs) {
element.bind('mouseenter', function() {
scope.$apply(attrs.enterEdit);
});
};
});
css
.box {
height:50px;
cursor:pointer;
color: #fff;
text-align: center;
}
.red {
background: red;
}
.blue {
background: blue;
}
Strange interaction, but okay. You need to not use the same scope for each directive since you want them to be isolated.
I just did this by creating a scope for a directive that has the shared template.
app.directive('why', function() {
return {
scope: {},
link: function($scope, elt, attrs) {
//setup in here
}, ...
A few other things:
Don't include angular through external resources and in the framework section of fiddle. It runs angular over your dom twice and will behave strangely.
Also there are ng-mouseenter and ng-mouseleave directives in angular so you don't need to implement those.
The updated fiddle is here
Hope this helped!