Issue with multiple child HTML elements using Directives in AngularJS - javascript

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.

Related

Reinitialize jssor slider

I am using angular js with jssor slider as follow.
As far as I am concern, there is no $destroy method for jssor slider yet. But I need the user to click on the refresh button and reinit the jssor slider.
As you can see, currently it won't work if i reinit the jssor slider by clicking the refresh function.
I do not want to call .remove() function and bind back the html as it seems to be less angular way. Is there any other method?
I can't create own $destroy method as the jssor slider library source code is uglify.
angular.module('app', [])
.controller('FrameController', ['$scope', '$injector', function($scope, $injector) {
initSlider();
$scope.refresh = initSlider;
function initSlider() {
var image = [];
var count = Math.floor(Math.random() * 6) + 1;
for (var i = 0; i < count; i++) {
image.push('https://unsplash.it/600/' + i * 100 + '?random');
}
$scope.image = image;
console.log($scope.image);
function jssor_slider1_init(containerId) {
var options = {
$AutoPlay: 1
};
var jssor_slider1 = new $JssorSlider$(containerId, options);
};
setTimeout(function() {
jssor_slider1_init('slider1_container');
});
}
}]);
setTimeout(function() {
angular.bootstrap(document.getElementById('body'), ['app']);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jssor-slider/25.2.0/jssor.slider.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<div id="body">
<div ng-controller="FrameController">
<button ng-click="refresh()">
Click to refresh
</button>
<div id="slider1_container" style="position: relative; top: 0px; left: 0px; width: 600px; height: 300px;">
<!-- Slides Container -->
<div u="slides" style="cursor: move; position: absolute; overflow: hidden; left: 0px; top: 0px; width: 600px; height: 300px;">
<div ng-repeat="item in image track by $index">
<img ng-src="{{item}}" /></div>
</div>
</div>
</div>

Angular Directive only works on one element at a time

I have the following angular directive. It uses a range slider to scroll a horizontal div of items. It works if applied to only one row. But if applied to multiple...nothing happens. The transclusion works, but function never runs and no errors are given. What can I do to this to make it be more angular universal and work on multiple elements? Here is repro:CodePen
app.directive('bob', function () {
return {
restrict: 'A',
transclude: true,
template:
`<div style="background-color: #333"><input type="range" value="0" id="scroll-rangeb"><div id="photo-containerb" style="display: flex; overflow-x: scroll; flex-direction: row; align-items: center; height: 90%;" ng-transclude></div></div>`,
link: function (scope, element, attrs) {
var scroll = document.getElementById("scroll-rangeb");
scroll.oninput = function () {
var panel = document.getElementById("photo-containerb");
var total = panel.scrollWidth - panel.offsetWidth;
var percentage = total * (this.value / 100);
panel.scrollLeft = percentage;
}
}
};
});
#scroll-rangeb is a unique element (in theory), if you override the oninput on every directive it clearly will not work, it'll remain only the first one found. Anyways, you mustn't use multiple components with the same id at all. Try to find it from the element parameter given on the link function instead, using classes or somthing else.
For example, I could get it solved by using element[0].getElementsByClassName('scroll-rangeb') :
angular.module('app', [])
.directive('bob', function() {
return {
restrict: 'A',
transclude: true,
template: `
<div style="background-color: #333">
<input type="range" value="0" class="scroll-rangeb">
<div
class="photo-containerb"
style="display: flex; overflow-x: scroll; flex-direction: row; align-items: center; height: 90%;"
ng-transclude>
</div>
</div>`,
link: function(scope, $element, attrs) {
var
element = $element[0],
scroll = element.getElementsByClassName("scroll-rangeb")[0],
panel = element.getElementsByClassName("photo-containerb")[0];
scroll.oninput = function() {
var total = panel.scrollWidth - panel.offsetWidth;
var percentage = total * (this.value / 100);
panel.scrollLeft = percentage;
}
}
};
});
img {
border-radius: 50%;
}
.box {
display: block;
width: 50px;
height: 50px;
min-width: 50px;
margin: 10px;
}
<div ng-app="app">
<div bob>
<img class="box" ng-repeat="img in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==">
</div>
<div bob>
<img class="box" ng-repeat="img in [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]" src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==">
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.js"></script>

Open/close div toggle and click outside div

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>

Angular Routing, Different background Images for each route page

I'm trying to set a different background image on the body of my separate partials.
But the images are just being loaded into the div area and not the whole body as i wanted, could any one of you be having an idea on how to solve this?
Here is my code
angular.module('controller',[])
app.controller('AboutCtrl',['$scope', function($scope){
$scope.title="The About page"
}])
app.controller('ServiceCtrl',['$scope', function($scope){
$scope.title="Our services page"
}])
app.controller('ContactCtrl',['$scope', function($scope){
$scope.title="How to contact us page"
}])
app.controller('MyCtrl', ['$rootScope', function ($rootScope) {
$rootScope.bgimg = "img/home.jpg";
}])
#bg {
position: fixed;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
}
#bg img {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
min-width: 50%;
min-height: 50%;
}
<body >
<div id="bg img" ng-controller="MyCtrl" style="background-image: url({{ bgimg }})">
</div>
</body
Can you not just move your main controller up to the body tag?
<body id="bg img" ng-controller="MyCtrl" style="background-image: url({{ bgimg }})">
<div ng-controller="OtherCtrl">
As I mentioned in my comments you create a service that holds the background variable. Then you create get/set methods to allow you to make changes.
var app = angular.module('controller',[])
.service('SessionService', function(){
var vm = this;
this.bgImg = "https://c1.staticflickr.com/1/31/37271521_47df0e4547_b.jpg";
return {
setBgImg: function(newBgImg){
vm.bgImg = newBgImg;
},
getBgImg: function(){
return vm.bgImg;
}
}
})
Then you inject the SessionService into the Main controller you have set on Body. And call the get method to retrieve the background variable.
app.controller('SessionCtrl', ['$scope','SessionService',function($scope, SessionService) {
this.getBgimg = SessionService.getBgImg;
}]);
<body id="bg img" ng-controller="SessionCtrl as vm" style="background-image: url({{ vm.getBgimg() }})">
Finally for every Controller you'd like to make the change, inject the service into the controller as well and call the Set method. In this example I have it being called from a button click function.
app.controller('ContactCtrl',['$scope','SessionService', function($scope,SessionService){
$scope.ContactTitle="How to contact us page";
$scope.winter = "";
$scope.changeBg = function(){
SessionService.setBgImg('http://alvaradoconsultinggroup.com/wp-content/uploads/2014/10/success.jpg');
}
}]);
<div ng-controller="ContactCtrl">
<p style="font-size: 25px;color: white;">{{ContactTitle}}</p>
<button ng-click="changeBg()">Change Back</button>
</div>
I piggybacked off Brian Baker's plunker to show you the changes in action here.
https://plnkr.co/edit/RjgwdwuOFJgMct4y3qUS?p=preview

Creating a directive and Isolating scopes in angular

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!

Categories