Calling function inside a directive in Angular - angularjs

Sorry If this question has been asked before, but my issue is bit different and hope someone can help me out.
1) I have a Directive which has many buttons. I want to call a function on this buttons and inside a directive. But I don't know how.
// Directive for the login header to avoid the duplication of the code
angular.module('App').directive('mainHeader',function(){
return{
restrict: 'AE',
template:'<h1 class="logo"> My App </h1>'+
'<button class="btn btn-primary">New User</button>'+
'<button class="btn btn-primary">New Product</button>'+
'<span class="dropdown" on-toggle="toggled(open)">'+
'<a href class="dropdown-toggle">'+
'<img class="userProfile" src="" alt="User Profile">'+
'<b class="caret"></b>'+
'</a>'+
// Here on my profile ????
'<ul class="dropdown-menu pull-right">'+
'<li> My Profile </a> </li>'+
'<li class="divider"></li>'+
// Here on my logout ??????
// This does not work
'<li> <a href="" ng-click="logOut()"> Sign Out </li>'+
'</ul>'+
'</span>'
}
});
My controller
(function() {
var logOutController = function($scope){
$scope.logOut = function(){
// Want to call this
}
logOutController .$inject = ['$scope'];
angular.module('App').controller('logOutController ',logOutController );
}());
And my view will be only one line
<div main-header></div>
I don't know how to do this
Update 1: -
Please have a look at the Plunker
http://plnkr.co/edit/YONVyVvNm4pQGFMU6SkG?p=preview.

You will just need to add an isolate scope to your directive:
// Directive for the login header to avoid the duplication of the code
angular.module('App').directive('mainHeader', function () {
return {
restrict: 'AE',
template: '<h1 class="logo"> My App </h1>' +
'<button class="btn btn-primary">New User</button>' +
'<button class="btn btn-primary">New Product</button>' +
'<span class="dropdown" on-toggle="toggled(open)">' +
'<a href class="dropdown-toggle">' +
'<img class="userProfile" src="" alt="User Profile">' +
'<b class="caret"></b>' +
'</a>' +
// Here on my profile ????
'<ul class="dropdown-menu pull-right">' +
'<li> My Profile </a> </li>' +
'<li class="divider"></li>' +
// Here on my logout ??????
// This does not work
'<li> <a href="" ng-click="logOut()"> Sign Out </li>' +
'</ul>' +
'</span>',
scope: {
'logOut': '&onLogOut' //<- this ties your directive's logOut function to an attr on the HTML tag
}
}
});
Then you just modify your HTML to:
<div main-header on-log-out="logOut()"></div>
Plunker Example

Related

Recursion angular directives

I need to use recursion in angular directives.
Follow the code with the template without recursion.
It is a left menu that must be created recursively.
I'm not sure how to put the recursion.
I tried '<leftmenu menuLeft = "itemmenu"> </ leftmenu>', but so only the profile image appears several times.
.directive('leftmenu', ['$compile', function ($compile) {
return {
retrict: 'E',
scope: { menuLeft: '=?' },
template: '<div class="user-panel">' +
'<div class= "pull-left image">' +
'<img src="{{ menuLeft.profileImgSrc }}" class="img-circle" alt="{{ menuLeft.profileName }}" />' +
'</div>' +
'<div class="pull-left info">' +
'<p>{{ menuLeft.profileName }}</p>' +
'</div>' +
'</div>' +
'<ul class="sidebar-menu">' +
'<li class="header">{{ menuLeft.header }}</li>' +
'<li class="treeview" ng-repeat="itemmenu in menuLeft.itens">' +
'<a href="{{ itemmenu.actionLink }}">' +
'<i class="{{ itemmenu.visualClass }}"></i> <span>{{ itemmenu.label }}</span>' +
'<span class="pull-right-container" ng-show="{{ itemmenu.subItems.length > 0 }}">' +
'<i class="fa fa-angle-left pull-right"></i>' +
'</span>' +
'</a>' +
'<ul class="treeview-menu">' +
'<li ng-repeat="subItem in itemmenu.subItems">' +
'<a ng-if="subItem.openInNewWindow" target="_blank" href="{{ subItem.actionLink }}">' +
'<i {{ subItem.class }}></i>{{ subItem.label }}' +
'</a>' +
'<a ng-if="!subItem.openInNewWindow" target="_self" href="{{ subItem.actionLink }}">' +
'<i {{ subItem.class }}></i>{{ subItem.label }}' +
'</a>' +
'</li>' +
'</ul>' +
'</li>' +
'</ul>',
compile: function (element) {
},
controller: function ($location, $http, $scope) {
$scope.menuLeft = {
"profileName": "",
"profileImgSrc": response.data.msgSaida[0].profileImgSrc,
"header": "",
"itens": response.data.msgSaida[0].itens,
"token": token
};
}
}
}
}
};
A little late to the party, if you're still looking to resolve this with a recursive directive, it depends what your data structure looks like, but assuming from what you've posted it looks like this:
{
"profileName": "",
...
"items": [{
"label": "title1",
"class": "class1",
"items: [...]
},{
"label": "title1",
"class": "class1",
"items: [...]
}]
}
You can split them into two directives:
One is the parent sidePanel directive that contains the top level
One is the menuList directive that will recursively display sub items
// profile image
// profile name
// etc
<menu-list items="leftMenu.items"></menu-list>
where menu list template was like:
<ul>
<li ng-repeat="item in items">
<span class="{{item.class}}">{{item.label}}</span>
<menu-list ng-if="item.items" items="item.items"></menu-list>
</li>
</ul>
So in each instance of a menu object (label,class,items) the items will be converted into a sub menu-list. You might need to play with it a little and add in some other features.

How to replace first element with different html in angular directive

Here is my directive:
.directive('iframeOnload', function() {
return {
restrict: 'A',
link: function(scope, elem){
var spinnerElement = angular.element(' <div id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
elem.replaceWith(spinnerElement);
angular.element('#appApprovalSpinner').addClass('ng-show');
elem.on('load', function(){
angular.element('#appApprovalSpinner').addClass('ng-hide');
});
}
};
});
and here is my html file where to use the directive
<div iframe-onload ></div>
<iframe id="appApprovedId" ng-if="approvalUrl" class="approve-iframe" ng-class="{'app-approved': isAppApproved}" ng-src="{{trustedApprovalUrl}}" iframe-onload></iframe>
I only want to replace the
<div iframe-onload ></div>
with
<div id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>'
and keep the iframe as it is because I want onLoad event is called when the iframe is finished loading.
Any suggestion how to replace on the only the div tag but not iframe tag.
Thanks
Instead of doing so much DOM manipulation, you can do this easily with ng-show and ng-hide, and keep track of things with a $scope variable that is assigned by the directive.
Change your directive a bit:
.directive('iframeOnload', function() {
return {
restrict: 'A',
link: function(scope, elem){
scope.ShowSpinner = true;
var spinnerElement = angular.element('<div ng-show="ShowSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
elem.append(spinnerElement);
elem.on('load', function(){
scope.ShowSpinner = false;
});
}
};
});
I made the following changes
Directive:
.directive('iframeOnload', function() {
return {
restrict: 'A',
scope: {
isRequired: '='
},
link: function(scope, elem){
var spinnerElement = angular.element(' <div ng-if="isApprovalRequired" id="appApprovalSpinner" class="row text-center approve-spinner"><i class="fa fa-spinner fa-pulse fa-5x fa-fw margin-bottom"></i></div>');
if ( (angular.element(elem).hasClass('spinner')) && scope.isRequired ) {
elem.replaceWith(spinnerElement);
}
angular.element('#appApprovalSpinner').addClass('ng-show');
elem.on('load', function(){
angular.element('#appApprovalSpinner').addClass('ng-hide');
});
}
};
});
and in the html file I have this
<div class="spinner" iframe-onload is-required="isApprovalRequired"></div>
<iframe id="appApprovedId" ng-if="approvalUrl" class="approve-iframe" ng-class="{'app-approved': isAppApproved}" ng-src="{{trustedApprovalUrl}}" iframe-onload></iframe>
It worked but still need the in there. Note It won't work if there is no tag there
Any solution to make it works without the extra tag ?

Html not being rendered in bootstrap popup when used with AngularJS scoped variable

In this fiddle :
http://jsfiddle.net/RLQhh/2695/
If click "Open Modal" the text "this is a new line" appears over two lines.
However If instead use this fiddle :
http://jsfiddle.net/RLQhh/2694/
The text "this is a <br> new line" appears over one line. The <br> element is not being rendered as html when used with a scoped variable.
I have set data-html="true" on both examples.
Why is this occurring ? How to render html when being applied using a scoped variable ?
fiddle src :
<div ng-controller="MainCtrl" class="container">
<h1>Modal example</h1>
<button ng-click="toggleModal()" class="btn btn-default">Open modal</button>
<modal title="Login form" visible="showModal">
<form role="form">
<div class="form-group">
<label data-html="true">{{text}}</label>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
</modal>
</div>
var mymodal = angular.module('mymodal', []);
mymodal.controller('MainCtrl', function ($scope) {
$scope.showModal = false;
$scope.text = "this is a <br> new line";
$scope.toggleModal = function(){
$scope.showModal = !$scope.showModal;
};
});
mymodal.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></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace:true,
scope:true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
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;
});
});
}
};
});

Not able to close modal window by function

I am using modal like
<modal title="Success" id='successmessage' visible="successmessage">
<form role="form">
Success ful result.
<button type="submit" class="btn btn-primary" ng-click="closesuccessmessage()" >Ok</button>
</form>
</modal>
I have a directive on modal..
'use strict';
angular.module('abc.directives', [])
.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">{{ modalTitle }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace:true,
scope:true,
link: function postLink(scope, element, attrs) {
scope.modalTitle = attrs.title;
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;
});
});
}
};
});
in my angular controller i have created function like below
$scope.closesuccessmessage = function()
{
$scope.successmessage = false;
}
But it does not have any effect. How can i make it work. As it is very important for me to control this from a function. Modal opens up on true value, but does not close on false value.
In order for angularjs to bind variable to view outside of properties expecting expressions you must use brackets.
<modal title="Success" id='successmessage' visible="{{successmessage}}">
<form role="form">
Success ful result.
<button type="submit" class="btn btn-primary" ng-click="closesuccessmessage()" >Ok</button>
</form>
</modal>
However I'm not sure visible is a valid property in HTML. If you want to hide modal using variable you could use ng-show and set success message variable in controller
<modal title="Success" id='successmessage' ng-show="successmessage">
<form role="form">
Success ful result.
<button type="submit" class="btn btn-primary" ng-click="closesuccessmessage()" >Ok</button>
</form>
</modal>
You can't use like above you're doing. You should call modal hide function to hide a modal. Try below snippet
$scope.closesuccessmessage = function()
{
$("#successmessage").modal('hide');
}
EDIT
It's not like that you can't use scope values in your HTML. If your controller is same, you can access it easily. I changed your HTML. Please try below one
<modal title="Success" id='successmessage' data-ng-show="successmessage">
instead
<modal title="Success" id='successmessage' visible="successmessage">

Conditional logic in ng-class in directives template

I'm using AngularJS and i'm writing my own directive. I want to use conditional logic in my custom directive. The problem is caused in the template part. Here's a piece of my code:
angular.module('myDirectives').directive('widget', function() {
return {
replace: true,
restrict: 'E',
template:
'<div class="widget">' +
'<div class="panel panel-default">' +
'<div class="panel-heading">' +
'<a href="" class="btn btn-default" ng-click="isCollapsed = !isCollapsed">' +
'<i class="fa" ng-class=" { 'fa-angle-up': !isCollapsed, 'fa-angle-down': isCollapsed } "></i>' +
'</a>' +
'</div>' +
'<div class="panel-body" collapse="isCollapsed">' +
'<p>Panel Content</p>' +
'</div>' +
'</div>' +
'</div>',
transclude: true
}
});
This line throws an error.
'<i class="fa" ng-class=" { 'fa-angle-up': !isCollapsed, 'fa-angle-down': isCollapsed } "></i>'
The '' around fa-angle-up and fa-angle-down are causing this.
There's probably a very simple workaround, but I haven't figured it out yet. So my question for you guys; Is there any other way to write this line?
You have to escape the apostrophes
'<i class="fa" ng-class=" { \'fa-angle-up\': !isCollapsed, \'fa-angle-down\': isCollapsed } "></i>'

Resources