I'm trying to fill the body attribute, so my module will print it as it's body part, yet I have no idea why it's not working, even I tried $scope.$apply() in several places.
var app = angular.module('ClientLogger', ['ngRoute'])
app.controller('global', function($scope, $compile) {
$scope.window = window
$scope.sampletext = "sampleText";
$scope.showModal = false;
$scope.toggleModal = function(text) {
$scope.text = text;
$scope.showModal = !$scope.showModal;
};
});
app.directive('modal', function() {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude> {{ body }} </div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace: true,
scope: true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.body = attrs.body;
scope.$watch(attrs.visible, function(value) {
if (value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
});
});
}
};
});
<body ng-app='ClientLogger' ng-controller='global'>
<a class="btn btn-default" ng-click="toggleModal(sampletext)"> sample </a>
<modal title="Message Details" body="{{text}}" visible="showModal"></modal>
</body>
As you can see, after i click the link, it will change the variable $scope.text and it will reflect to the modal. But I can't manage to do it. Since I#m very new about this Angular, I still have troubles about understanding its mechanics, so any specific details will be really good for me.
Any recommendations?
When you retrieve your attrs.body, you are retrieving undefined data.
You can use a Factory to share your data. You have to know that all angular services are singletons, so there is only one instance of a given service.
Thanks to this, you can easily share your data between your controller and your directive.
So when you will trigger an action in your Controller, you will set your data into your factory, then you can retrieve your data into your directive.
Controller
(function(){
function Controller($scope, Service) {
$scope.myText = 'sample';
$scope.showModal = false;
$scope.toggleModal = function() {
//Set the myText value by using our Service.set() method
Service.set($scope.myText);
$scope.showModal = !$scope.showModal;
};
}
angular
.module('app', [])
.controller('ctrl', Controller);
})();
Service
(function(){
function Service(){
var data;
function set(value){
data = value;
}
function get(){
return data;
}
return {
get: get,
set: set
};
}
angular
.module('app')
.factory('Service', Service);
})();
Directive
(function(){
function modal(Service) {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body"> {{ body }} </div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace: true,
scope: true,
link: function (scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value) {
value
//Retrieve your data by using Service.get() method, and show our modal
? ( scope.body = Service.get(), $(element).modal('show') )
: $(element).modal('hide')
});
$(element).on('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
});
});
}
};
}
angular
.module('app')
.directive('modal', modal);
})();
Then, you can call your directive into your HTML.
HTML
<body ng-app='app' ng-controller="ctrl">
<input type="text" ng-model="myText">
<a class="btn btn-default" ng-click="toggleModal()"> sample </a>
<modal title="Message Details" visible="showModal"></modal>
</body>
You can see the Working Plunker
Related
I have buttons like submit, reject and cancel. If i click on this button a small div with comment shows up and a ok and cancel button will be shown. On click of ok popup with 'are you sure' message popups up.
<button type="button" ng-click="showDiv = !showDiv">Submit
</button>
<button type="button" ng-click="showDiv = !showDiv">Reject
</button>
I am using a popup modal directive like this for the small div as i mentioned above:
<div ng-show="showDiv">
<yes-no msg="are you sure"></yes-no>
</div>
Now I want to change the msg on click of each button. Suppose if i click 'Submit' my msg should be 'are you sure to submit' if i click 'reject' my msg should be 'are you sure to reject'.
directive:
mainapp.directive('yesNo', function($modal){
return {
restrict: 'A',
scope: {
msg: '#msg'
},
link: linkFn
};
function linkFn(scope, element, attrs) {
var msg = attrs.msg;
var modalTemplate = '<div class="modal-content">' +
' <div class="modal-body">' +
' <h4 class="modal-title">' + msg + '</h4>' +
' </div>';
var modalInstance = $modal.open({
template: modalTemplate,
controller: 'yesNoModalCtrl'
});
});
}
});
How to achieve this? I will not be able to post the code here.
<input type="button" name="submit" ng-click="buttonclick('are you sure to submit')"/>
<input type="button" name="reject" ng-click="buttonclick('are you sure to reject')"/>
<div ng-show="showDiv">
<yes-no msg={{message}}></yes-no>
</div>
In you main controller:
app.controller("mainController", function($scope){
$scope.message="";
$scope.buttonclick = function(msg){
$scope.message= msg;
}
});
app.directive("yesNo", function(){
return{
restrict: 'E',
scope:{
msg:'#'
},
link: linkFn,
controller: 'yesNoModalCtrl'
}
});
In directives Link function
function linkFn(scope, element, attrs) {
attrs.$observe('msg', function(msg) {
// this function gets triggered each time "msg" is changed
// You can do whatever you want here
if (msg) {
var modalTemplate = '<div class="modal-content">' +
' <div class="modal-body">' +
' <h4 class="modal-title">' + msg + '</h4>' +
' </div>';
var modalInstance = $modal.open({
template: modalTemplate,
controller: 'yesNoModalCtrl'
});
}
});
}
plunker
Create a controller function:
$scope.showModal = function(msg) {
$scope.showDiv = !$scope.showDiv;
$scope.msg = msg;
}
And in your buttons:
<button type="button" ng-click="showModal('Are you sure')">Submit
</button>
<button type="button" ng-click="showModal('Some other text')">Reject
</button>
<div ng-show="showDiv">
<yes-no msg="msg"></yes-no>
</div>
Everything seems to render properly but my ng-click="check($event)" is not firing when I click on one of the four buttons. I even added an alert to the check($event) function but it's not coming up. Heres the codepen http://codepen.io/theMugician/pen/MKOzzV?editors=101
simonApp.directive('pads', ['lightIt', 'soundIt', function(lightIt,soundIt) {
var template = '';
template += '<button ng-click="check($event)" id=' + '{{index}} ' + 'class="pad pad-' + '{{color}}' + '">';
template += '<div class="ripple js-ripple">';
template += '<span class="ripple-circle ' + 'ripple-' + '{{color}}' + '"></span></div>';
template += '</button>';
return {
restrict: 'E',
replace: true,
scope: {
color: '#color',
index: '#index'
},
link: function(scope, element, attrs) {
scope.createRipple = function(e){
lightIt.createRipple(e, this);
}
//scope.$emit('index', scope.index);
/*
var index = parseInt(scope.index);
scope.playSound = function() {
soundIt(1);
}*/
console.log("scope.index: " + scope.index);
//console.log("scope.playSound: " + scope.playSound);
element.on('click', scope.createRipple);
//element.on('animationend', scope.endRipple);
},
template: template
};
}]);
Here is the check() function in the controller
$scope.check = function(e) {
alert("check works");
var id = e.currentTarget.id;
if($scope.init){
if(sequence[turn] === id){
turn++;
if(turn === sequence.length){
$scope.step++;
setTimeout(function(){
newRound();
}, 1000);
}
}else{
if($scope.isStrict){
setTimeout(function(){
alert('game over');
$scope.reset();
}, 300);
}else{
$scope.displaySeq(sequence);
}
}
}
}
You cannot call controller method from directive like that.
In case you need scope isolation you have to use expression binding ( '&' scope parameters) or turn off scope isolation all together ( remove scope key from directive definition )
See excellent video from John Lindquist for example of using scope expression binding.
var app = angular.module('app', [])
app.directive("pads", function() {
return {
restrict: "E",
scope: {
check: "&"
},
template: '<div class="button" ng-click="check({message: value})">click</div></div>',
link: function(scope) {
scope.value = 'message to controller'
}
};
});
app.controller('myCtrl', function() {
this.doCheck = function(message) {
alert(message) // alerts "message to controller"
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app' ng-controller='myCtrl as ctrl'>
<pads check="ctrl.doCheck(message)"></pads>
</div>
I want to use the abilitie of ui-router to test the active state in a ng-class
If I try this it does not work :
navTest.$inject = ["$compile", "$navbar", "$state"];
function navTest($compile, $navbar, $state) {
var defaults = $navbar.defaults;
var navTest = {
restrict: 'E',
template: '<nav class="navbar navbar-default" role="navigation">' +
'<div class="container-fluid">' +
'<div class="navbar-header">' +
'<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">' +
'<span class="sr-only">Toggle navigation</span>' +
'<span class="icon-bar"></span>' +
'<span class="icon-bar"></span>' +
'<span class="icon-bar"></span>' +
'</button>' +
'<a class="navbar-brand" href="#">Brand</a>' +
'</div>' +
'<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">' +
'<ul class="nav navbar-nav">' +
'<li data-ng-class="{active: $state.includes(\'user\')}"><a data-ui-sref="user.List">Link 1</a></li>' +
'<li data-ng-class="{active: $state.includes(\'technology\')}"><a data-ui-sref="technology.List">Link 2</a></li>' +
'</ul>' +
'</div>' +
'</div>' +
'</nav>',
replace: true
};
return navTest;
}
Now if I add a function to test the active state in the "link" function
(of the directive) and I replace : data-ng-class="{active: $state.includes(\'technology\')}" by data-ng-class="{active: isActiveState(\'technology\')}"
link : function (scope, elem, attrs) {
scope.isActiveState = function (name) {
return $state.includes(name);
};
}
Everything works fine but I don't understand why because the function does exactly the same thing ?
It's a scope thing but you don't want to use $rootScope; putting the following in your link function should be enough:
scope.$state = $state;
That's because $state is not on your scope. What I recommend is that you add a reference to $state in your scope (using your link function). If you are likely to need $state in several places, I suggest you add it to the $rootScope using the run function of your module / application:
angular
.module('yourModule')
.run([
'$rootScope',
'$state',
function ($rootScope, $state) {
$rootScope.$state = $state;
}
]);
You can use ui-router filters in template.
https://github.com/angular-ui/ui-router/wiki/Quick-Reference#filters-1
In your case:
ng-class="{ active: 'user' | includedByState }"
I made a directive that compiles a 'div' with an ng-include and ng-controller, and appends it to the element. It works fine, but for some reason the "$destroy" event isn't called on the controller's scope when it is destroyed.
Is what I'm doing correct?
This is the html:
<my-Directive tr-model="someBindedObject"></my-Directive>
And this is the JS:
angular.module('myModule').
directive('myDirective', function ($compile, controllerMapper) {
function compileTemplate(scope, element, attrs) {
var controller = controllerMapper.getController(scope.model);
innerHtml = '<div ng-include src="' + "'" + controller.templateUrl + "'" + '" ng-controller="' + controller.controllerName + '" ></div>';
var innerElement = $compile(innerHtml)(scope);
element.empty();
element.append(innerElement);
};
return {
scope: {
model: "=trModel"
},
link: compileTemplate
}
}).
controller('myController', function($scope){
$scope.$on('$destroy', function () {
//this is never called
});
});
I try to make my own button using directive.
The dialog (bootstrap.dialog) should be hired after clicking the button.
But, it won't.
Tried without click event, it works.
Using this:
- AngularJS v1.0.8
- Bootstrap 2.3.2
- Angular-bootstrap 0.3.0
here's my directive...
.directive("ucayButton", function($dialog) {
return {
restrict: 'EA',
template: '<button ng-transclude></button>',
replace: true,
transclude: true,
link: function(scope, element, attrs) {
element.addClass('btn btn-primary');
var t = '<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" ng-click="close()" aria-hidden="true">×</button>' +
'<h4 class="modal-title">Modal title</h4>' +
'</div>' +
'<div class="modal-body">' +
'<p>One fine body…</p>' +
'</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-default" ng-click="close()">Close</button>' +
'<button type="button" class="btn btn-primary" ng-click="close()">Save changes</button>' +
'</div>' +
'</div><!-- /.modal-content -->' +
'</div><!-- /.modal-dialog -->';
var modalOpts = {
backdrop: true,
keyboard: true,
backdropClick: true,
template: t,
controller: 'dialogCtrl'
};
scope.openDialog = function(){
console.log('confirmation called'); //always shown when function was called
var d = $dialog.dialog(modalOpts);
d.open().then(function(result){
if(result)
{
alert('dialog closed with result: ' + result);
}
});
};
angular.forEach(element, function(el) {
el.addEventListener('click', function() {
scope.openDialog(); // the function was hired, but the dialog didn't
});
});
scope.openDialog(); //hired
}
};
})
addEventListener is not an angular function, so when you perform code that affects $scope variables you need to get those changes back into the digest cycle.
Try this instead:
el.addEventListener('click', function() {
if(scope.$$phase) {
scope.openDialog();
} else {
scope.$apply(function() {
scope.openDialog();
});
}
});
This checks the $$phase of the scope, which is truthy if you are running code from within a digest cycle. If you are already in a digest cycle then there is no need to wrap the code with an $apply call. If you are not then wrapping the code in an $apply call lets angular know that it needs to digest the changes you are making.