Alert directive not showing after it has been rendered once - angularjs

I have a directive to display an alert message every time a post call succeeds/fails. The alert for the first post always succeeds but if I close the alert, and trigger another post the alerts don't show anymore.
Some code below:
Include tag in html
<alert message="notification"></alert>
Directive
app.directive("alert", function(){
return{
restrict: 'EA',
templateUrl: "alert.html",
replace: false,
transclude: false,
scope: {
message: "=",
close: "&"
},
link: function(){
}
};
});
Template
<div class="alert alert-{{message.type}}" ng-show="message.text">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<div>{{message.text}}</div>
</div>
UPDATE: http://plnkr.co/edit/mECmQNSgW0EdXZGPmkNx?p=preview
Any thoughts?
Thanks in advance.

Instead of using data-dismiss="alert" you can have your close button call the close function. The close function can then clear the notifications since you have $scope.notification in the isolated scope as scope.message:
var app = angular.module('app', []);
app.controller('AlertDemoCtrl', function($scope) {
$scope.notification = {};
$scope.alertNotif = function() {
$scope.notification.type = "error";
$scope.notification.text = "demo text";
};
});
app.directive("alert", function() {
return {
restrict: 'EA',
template: '<div class="alert alert-{{message.type}}" ng-show="message.text">' +
'<button type="button" class="close" ng-click="close()" aria-hidden="true">×</button>' +
'<div>{{message.text}}</div>' +
'</div>',
replace: false,
transclude: false,
scope: {
message: "=",
close: "&"
},
link: function(scope) {
scope.close = function() {
scope.message = {};
}
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<!-- jQuery -->
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.4/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-controller="AlertDemoCtrl">
<button ng-click="alertNotif()">test</button>
<alert message="notification"></alert>
</div>
</body>
</html>

Per the Bootstrap documentation (emphasis mine):
… Closing an alert removes it from the DOM.
Because it's removed from the DOM it will not show up again...

Related

I am facing problem in this code of custom directive

I am written this code for angularjs custom directive, but not geeting the output. Please help me.strong text
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script src="angular-1.7.6\angular.js"></script>
<script src="angular-1.7.6\angular.min.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('mycolor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<my-c title="{{c}}">
BASIC COLOR:
</my-c>
</div>
</div>
</body>
</html>
Iam not getting where I am wrong.
I am getting the output as
Output
The code is as below :
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('mycolor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<mycolor title="{{c}}">
BASIC COLOR:
</mycolor>
</div>
</div>
</body>
</html>
Firstly change the name of the directive into camelCase, it's a good convention for naming directives. So your directive name should be myColor.
Then use the directive like - my-color. Below is the whole code -
<html>
<head>
<title>Directives</title>
<script src="https://code.angularjs.org/1.6.9/angular.js"></script>
<script>
var app=angular.module("arrayApp", [])
app.controller("arrayCtrl", function ($scope) {
$scope.colors = ["RED","GREEN","BLUE","YELLOW" ];
});
app.directive('myColor', function() {
return {
restrict: 'E',
transclude: 'true',
template: '<span ng-transclude></span>',
link: function(scope, element, attr){
element.append("<strong>"+attr.title+"</strong>");
}
};
});
</script>
</head>
<body ng-app="arrayApp">
<div ng-controller="arrayCtrl">
<div ng-repeat="c in colors">
<my-color title="{{c}}">
BASIC COLOR:
</my-color>
</div>
</div>
</body>
</html>
This is the output -

Can't get transclude data binding working

I just made an example of how I am trying to use transclude data binding. Well, after binding an object (message) from controller scope its "undefined" in directive's link function.
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script>
angular.module('myApp', []).controller('myAppController', function($scope)
{
$scope.message = { text: 'hello'}
});
angular.module('myApp').directive('myDirective', function() {
return {
restrict: 'E',
template: "<div><div ng-transclude></div></div>",
transclude: true,
scope: { message: "=" },
link: function (scope) {
// Its undefined here
console.log(scope.message);
}
};
})
</script>
</head>
<body ng-controller="myAppController">
<my-directive>
{{message.text}}
</my-directive>
</body>
</html>
Any help would be appreciated, Thanks
[EDIT]
Maybe I have not been too clear. Actually my code is kinda:
Home.html
Sorry, maybe I have not been too clear. Actually my code is KINDA:
<html ng-app="myApp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<script>
angular.module('myApp', []).controller('myAppController', function($scope)
{
$scope.model = { id: 100, name: "name"}
});
angular.module('myApp').directive('myDirective', function() {
return {
restrict: 'E',
templateUrl: "Modal.html",
transclude: true,
scope: { model: "=" },
link: function (scope) {
// Its undefined here
console.log(scope.model);
}
};
})
</script>
</head>
<body ng-controller="myAppController">
<my-directive>
<div>
id:<input type="text" ng-model="model.id" />
name:<input type="text" ng-model="model.name" />
<button class="btn btn-primary" ng-click="doIt()">do something</button>
</div>
</my-directive>
</body>
</html>
Modal.html
<div class="modal-header">
<h3 class="modal-title">Edit modal</h3>
</div>
<div class="modal-body">
<div ng-transclude>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="btnModalGravar()">Gravar</button>
<button class="btn btn-warning" ng-click="btnModalCancelar()">Cancelar</button>
</div>
Im just wondering why "console.log(scope.model)" returns "undefined" in directive's link function after using scope: { model: "=" }
angular.module('myApp').directive('myDirective', function() {
return {
restrict: 'E',
template: "<div><div ng-transclude></div></div>",
transclude: true,
scope: { message: "=" },
link: function (scope) {
}
};
})
//Html
<my-directive message="message">
{{message.text}}
</my-directive>
If you are trying to pass some data to directive it's not a translusion but an isolated scope. You've almost got it. Just use your directive like this:
<body ng-controller="myAppController">
<my-directive message="message"></my-directive>
<!-- This way you're referencing your $scope.message object, so it's like you've had:
<my-directive message="{text: 'hello'}"></my-directive>
-->
</body>
Transclusion is used to pass not some data but some markup (i.e. html, other directives).
If you want to use transcluded content inside your linking function, you should use it as a 5th parameter of this function, like this:
// Directive excerpt
return {
...
transclude: true,
link: function(scope, el, attrs, ctrl, transclude) {
var transcluded = transclude();
console.log(transcluded);
}
};
// View excerpt
<my-directive message="message">
<span>{{ message.text }}</span>
</my-directive>
You can take a look at Isolating the Scope of a Directive section in angular documentation Creating Custom Directives

ng-hide breaking my directive in angular 1.3.16

I'm trying to migrate from angular 1.2.28 to angular 1.3.16, however my code broke.
Angular 1.2.28 working: http://plnkr.co/edit/XfVakwA3Upm7Z2wosHCQ?p=preview
Angular 1.3.16 not working: http://plnkr.co/edit/4VxcHL0MHddobkmu9DMG?p=preview
JS
var app = angular.module('app', []);
app.run(function($rootScope, $timeout){
$rootScope.loading = true;
$timeout(function(){
$rootScope.items = ['Angular', '1.3.16', 'doesnt work'];
$rootScope.loading = false;
}, 3000);
});
app.directive('refresh', function(){
return {
restrict: 'A',
require: '^myDirective',
link: function(scope, element, attrs, ctrl){
if(scope.$last)
ctrl.init();
}
};
});
app.directive('myDirective', function(){
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
controller: function($scope, $element){
this.init = init;
function init(){
$scope.myHeight = $('.my-directive').height();
}
}
};
});
HTML
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
<script data-require="jquery#1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Angular 1.3.16</h1>
<div ng-show="loading">Loading...</div>
<my-directive ng-hide="loading">
<div ng-repeat="item in items" refresh>
<p>{{item}}</p>
</div>
</my-directive>
</body>
</html>
The idea is to only run certain code when the inner html is outputted.
Height is 0 in angular 1.3.16.
However, if I remove ng-hide="loading" from <my-directive ng-hide="loading"> in angular 1.3.16, height gets the appropriated value.
Any ideas how can I solve this?
Inject $timeout into your directive and put the init code block in $timeout(function(){ ... }) like this:
app.directive('myDirective', function($timeout){
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p><b>Height: {{myHeight}}</b></p> <div ng-transclude></div></div>',
controller: function($scope, $element){
this.init = init;
function init(){
$timeout(function(){
$scope.myHeight = $('.my-directive').height();
});
}
}
};
});
var app = angular.module('app', []);
app.run(function($rootScope, $timeout) {
$rootScope.loading = true;
$timeout(function() {
$rootScope.items = ['Angular', '1.3.16', ' work'];
$rootScope.loading = false;
}, 1000);
});
app.directive('myDirective', function($timeout) {
return {
restrict: 'E',
replace: true,
transclude: true,
template: '<div class="my-directive"><p>Height: {{myHeight}}</p> <div ng-transclude></div></div>',
link: function($scope, $element) {
$element.on('DOMAttrModified DOMSubtreeModified', init);
function init() {
$scope.$apply(function() {
$scope.myHeight = $element.height();
});
}
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="jquery#1.11.0" data-semver="1.11.0" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script data-require="angular.js#1.3.16" data-semver="1.3.16" src="https://code.angularjs.org/1.3.16/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<h1>Angular 1.3.16</h1>
<div ng-show="loading">Loading...</div>
<my-directive ng-hide="loading">
<div ng-repeat="item in items" refresh>
<p>{{item}}</p>
</div>
</my-directive>
</body>
</html>
You have to set the height in the correct angular directive phase/lifecycle. You should set the hight in the link or even postlink phase. Usually the two phases are the same if you don't use prelink This is when all the content has already been rendered. See angular $compile or google for angular post link
The controller is for the logic and the link is for html/dom manipulations.
EDIT:
You can bind 'DOMAttrModified DOMSubtreeModified` events to trigger changes.

how to call the directive on button click inside custom directive

Hi i am working on custom directives of angularjs. I just want to know that how to call the directive when I click the button. Please suggested me how to achieve this.
Thanks
<div ng-controller="ctrl">
<mydirc></mydirc>
<button ng-click="clickMe()">call clickMe()</button>
</div>
app.directive('mydirc', function() {
return {
restrict: 'E',
replace: true,
template: '<div></div>',
link: function($scope, element, attrs) {
$scope.clickMe= function() {
alert('inside click');
}
}
}
});
The following example shows a sample custom directive which can handle click events; This is a scope-independent directive. And the appRoot module has to be defined earlier.
<div ng-controller="MyController">
<button custom-click="">Click Me</button>
</div>
appRoot.directive('customClick', function() {
return {
link: function(scope, element, attrs) {
element.click(function(){
//Do something useful
});
}
}
});
By "calling" the directive I am going to assume you mean handling the onclick event from the directive.
You can leverage the 'link' property of directives to attach scope initialization and functions like so:
http://jsbin.com/moruyoso/2
HTML
<!DOCTYPE html>
<html ng-app='app'>
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div clicker></div>
</body>
</html>
JS
var app = angular.module('app', []);
app.directive('clicker', function(){
var link = function(scope){
scope.showMessage = function(){
alert('you clicked the directive!');
};
};
return{
link: link,
template: "<button ng-click='showMessage()'>Click me!</button>"
};
});
This example shows how to handle a click event for more than one button inside a directive:
Java Script: ( app.js )
angular.module('app', [])
.controller("articles.controller", function(){
var viewModel = this;
viewModel.articles =
[
{
title: "PHP",
content: "content 1",
selected: false
},
{
title: "C#",
content: "content 2",
selected: false
}
];
viewModel.addArticle = function(){
viewModel.articles.push(
{
title: "MySQL",
content: "new content",
selected: false
}
);
};
viewModel.select = function(article){
article.selected = !article.selected;
};
viewModel.getAll = function(){
console.clear();
console.log(viewModel.articles);
};
viewModel.getSelected = function(){
console.clear();
angular.forEach(viewModel.articles, function(article, key){
if(article.selected)
{
console.log(article.title);
}
});
};
})
.directive("artilceTile", function(){
return {
restrict: 'E',
scope: {
article: '='
},
link: function(scope, element, attr)
{
scope.displayTitle = function()
{
alert(scope.article.title);
},
scope.displayContent = function()
{
alert(scope.article.content);
},
scope.inverseArticleStatus = function()
{
scope.article.selected = !scope.article.selected;
}
},
template: `
<h1>{{article.title}}</h1>
<p>{{article.content}}</p>
<p ng-if="article.selected">Selected</p>
<input ng-model=article.title>
<button ng-click="displayTitle()">Dispaly Title</button>
<button ng-click="displayContent()">Display Content</button>
<button ng-click="inverseArticleStatus()" ng-if="!article.selected">Select</button>
<button ng-click="inverseArticleStatus()" ng-if="article.selected">Unselect</button>
<br><br><br><hr>
`
};
});
HTML: ( index.html )
<!DOCTYPE html>
<html ng-app="app">
<head>
<title></title>
</head>
<body>
<div ng-controller="articles.controller as articlesController">
<span ng-repeat="article in articlesController.articles">
<artilce-tile article="article"></artilce-tile>
</span>
<br><br>
<button ng-click="articlesController.addArticle()">Add New Article</button>
<button ng-click="articlesController.getSelected()">Get Selected Articles</button>
<button ng-click="articlesController.getAll()">Get All Articles</button>
</div>
<script type="text/javascript" src="angular.js"></script>
<script src="app.js"></script>
</body>
If you mean to ask how to show a directive template on button click, use a variable in the controller scope to show/hide it and update the variable on button click.
<div ng-controller="ctrl">
<mydirc ng-show="showMydirc"></mydirc>
<button ng-click="clickMe()">call clickMe()</button>
</div>
app.controller("ctrl", function($scope){
$scope.showMydirc=false;
$scope.clickMe = function(){
$scope.showMydirc = true;
}
});

Modal in angular lets user click out of it

I have a modal dialog in my angularJS app, but when the user clicks on the greyed out site behind the modal, the modal closes. I want the modal to behave like a modal, ie, you have to respond to what's inside in order to get it to close. Can anyone tell me how to achieve this? Here is a jsbin:
http://jsbin.com/aDuJIku/2/edit
EDIT: Code for future reference:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.4/angular.js"></script>
<meta charset=utf-8 />
<title>JS Bin</title>
</head>
<body ng-app='ModalDemo'>
<div ng-controller='MyCtrl'>
<button ng-click='toggleModal()'>Open Modal Dialog</button>
<modal-dialog show='modalShown' width='400px' height='60%'>
<p>Modal Content Goes here<p>
</modal-dialog>
</div>
</body>
</html>
app = angular.module('ModalDemo', []);
app.directive('modalDialog', function() {
return {
restrict: 'E',
scope: {
show: '='
},
replace: true, // Replace with the template below
transclude: true, // we want to insert custom content inside the directive
link: function(scope, element, attrs) {
scope.dialogStyle = {};
if (attrs.width)
scope.dialogStyle.width = attrs.width;
if (attrs.height)
scope.dialogStyle.height = attrs.height;
scope.hideModal = function() {
scope.show = false;
};
},
template: "<div class='ng-modal' ng-show='show'><div class='ng-modal-overlay' ng-click='hideModal()'></div><div class='ng-modal-dialog' ng-style='dialogStyle'><div class='ng-modal-close' ng-click='hideModal()'>X</div><div class='ng-modal-dialog-content' ng-transclude></div></div></div>"
};
});
app.controller('MyCtrl', ['$scope', function($scope) {
$scope.modalShown = false;
$scope.toggleModal = function() {
$scope.modalShown = !$scope.modalShown;
};
}]);
Assuming you're using Bootstrap set the backdrop to static.
var modalInstance = $modal.open({
templateUrl: '/App/Documents/Templates/DeleteDocumentDialogTemplate.html',
backdrop: 'static'
});
In this section of your directive's template, remove ng-click='hideModal()' and you're done.
<div class='ng-modal-overlay' ng-click='hideModal()'>

Resources