Conditional logic in ng-class in directives template - angularjs

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>'

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.

AngularJS Issue with custom directive to upload excel

I am using ng-admin and I created a custom directive(following this example http://plnkr.co/edit/rYC3nd7undqJz2mr8Old) to upload a excel sheet, when I upload the file, I get the following TypeError: Cannot set property 'columnDefs' of undefined, my code
Module:
var myApp = angular.module('myApp', ['ng- admin','ngStorage','chart.js','ui.grid']);
Controller
myApp.controller('MainCtrl', ['$scope', function ($scope) {
var vm = this;
vm.gridOptions = {};
vm.reset = reset;
function reset() {
vm.gridOptions.data = [];
vm.gridOptions.columnDefs = [];
}
}]);
Directive:
myApp.directive('fileread', ['$http', function ($http) {
return {
restrict: 'E',
scope: {
opts: '='
},
link: function ($scope, $elm, $attrs) {
$elm.on('change', function (changeEvent) {
var reader = new FileReader();
reader.onload = function (evt) {
$scope.$apply(function () {
var data = evt.target.result;
var workbook = XLSX.read(data, {type: 'binary'});
var headerNames = XLSX.utils.sheet_to_json( workbook.Sheets[workbook.SheetNames[0]], { header: 1 })[0];
var datasheet = XLSX.utils.sheet_to_json( workbook.Sheets[workbook.SheetNames[0]]);
console.log(datasheet);
$scope.opts.columnDefs = [];
headerNames.forEach(function (h) {
$scope.opts.columnDefs.push({ field: h });
});
$scope.opts.data = datasheet;
var json_string = JSON.stringify($scope.opts.data);
console.log(json_string);
$elm.val(null);
});
};
reader.readAsBinaryString(changeEvent.target.files[0]);
});
}, template:
'<div ng-controller="MainCtrl as vm">'+
'<button type="button" class="btn btn-success"
ng-click="vm.reset()">Reset Grid</button>'+
'<br />'+
'<br />'+
'<div id="grid1" ui-grid="vm.gridOptions" class="grid">'+
'<div class="grid-msg-overlay"
ng-show="!vm.gridOptions.data.length">'+
'<div class="msg">'+
'<div class="center">'+
'<span class="muted">Select Spreadsheet File</span>'+
'<br />'+
'<input type="file" accept=".xls,.xlsx,.ods" fileread="" opts="vm.gridOptions" multiple="false" />'+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</div>'
}
}]);
Template from I am calling the directive
var customDashboardTemplate =
'<div class="row dashboard-starter"></div>' +
'<question-stats></question-stats>'+
'<div ng-controller="MainCtrl" >'+
'<fileread>'+
'<button type="button" class="btn btn-success" ng-click="reset()">Reset Grid</button>'+
'<br />'+
'<br />'+
'<div id="grid1" ui-grid="gridOptions" class="grid">'+
'<div class="grid-msg-overlay" ng-show="!gridOptions.data.length">'+
'<div class="msg">'+
'<div class="center">'+
'<span class="muted">Select Spreadsheet File</span>'+
'<br />'+
'<input type="file" accept=".xls,.xlsx,.ods" fileread="" opts="gridOptions" multiple="false" />'+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</fileread>'+
'</div>'+
'<div class="row dashboard-content">' +
'<div class="col-md-6">' +
'<div class="panel panel-green">' +
'<ma-dashboard-panel collection="dashboardController.collections.last_users" entries="dashboardController.entries.last_users" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
'</div>' +
'</div>'+
'<div class="col-md-6">' +
'<div class="panel panel-yellow">' +
'<ma-dashboard-panel collection="dashboardController.collections.last_tips" entries="dashboardController.entries.last_tips" datastore="dashboardController.datastore"></ma-dashboard-panel>' +
'</div>' +
'</div>'+
'</div>'+
'</div>'
;
It may just be the space inside the template separating the ng-click calling the reset function:
(ng- click)
With that space you are not calling the reset therefore not actually assigning the defaults?
Edit:
You are calling the directive within the directive within the directive's template. This seems fishy. Can we see the HTML implementation of where you are calling the directive?

Calling function inside a directive in Angular

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

How to make the ionic radio toggle on/off?

I want the user to be able to toggle one option. If they toggle to another option within a section, it will toggle the other previously made selection to off. A user will also be able to deselect their selection (i.e).
Steps:-
Tap button 1(button 1 turns "off" to "on")
Tap button 1 again(it should turn "On" to "Off")
I used the following code
app.directive('kmItoggleRadio', function() {
return{
restrict:'E',
compile: function(element,attrs)
{
var leftTitle='';
if(angular.isUndefined(attrs.kmLeftTitle)) {
leftTitle='';
}
else {
leftTitle=attrs.kmLeftTitle;
}
var rightTitle='';
if(angular.isUndefined(attrs.kmRightTitle)) {
rightTitle='';
}
else {
rightTitle=" "+attrs.kmRightTitle ;
}
var show='false';
if(angular.isUndefined(attrs.kmShow)) {
show="true";
}
else {
show=attrs.kmShow;
}
var htmlText='<div><div ng-switch on="format">'+
'<div ng-switch-when="kmForm">'+
'<div ng-show='+show+'>'+
'<ul class="list">'+
'<li class="item item-toggle">'+
''+leftTitle+''+
'<label class="toggle toggle-positive">'+
'<input type="radio" value="'+attrs.kmValue+'" ng-model="'+attrs.kmModel+'" >'+
'<div class="track">'+
'<div class="handle"></div>'+
'</div>'+
'</label>'+
'</ul>'+
'</div>'+
'</div>'+
'<div ng-switch-when="kmPreview">'+
'<div ng-show='+show+'>'+
'<ul class="list">'+
'<li class="item item-toggle">'+
''+leftTitle+''+
'<label class="toggle toggle-positive">'+
'<input type="checkbox" disabled="true" value="'+attrs.kmValue+'" ng-model="'+attrs.kmModel+'">'+
'<div class="track">'+
'<div class="handle"></div>'+
'</div>'+
'</label>'+
'</ul>'+
'</div>'+
'</div>'+
'</div></div>';
element.replaceWith(htmlText);
}
}
})
In HTML
<km-itoggle-radio km-model="a.c" km-value="d" km-left-title="Dhoni"></km-itoggle-radio>
<km-itoggle-radio km-model="a.c" km-value="s" km-left-title="Kohli"></km-itoggle-radio>
I want to know how to make the radio button toggle on/off by tapping the button again (with out tapping the other button in same group).
Why not use the built in ion-toggle?
Ionic toggle Codepen Demo
<ion-toggle ng-repeat="item in settingsList"
ng-model="item.checked"
ng-checked="item.checked">
{{ item.text }}
</ion-toggle>

Using ngOptions inside directive

I have the following shuttle boxes directive:
<shuttle-boxes ng-options="item for item in itemList" ng-model="myModel" />
My template looks like this:
template: '<div class="shuttle-boxes">' +
'<select multiple="multiple" class="shuttle-boxes-left"></select>' +
'<button class="shuttle-boxes-btn" type="button"><i class="icon icon-arrow-right"></i></button>' +
'<button class="shuttle-boxes-btn" type="button"><i class="icon icon-arrow-left"></i></button>' +
'<select multiple="multiple" class="shuttle-boxes-right"></select>' +
'</div>'
What I want to do is take the ng-options repeater from <shuttle-boxes> and use it to populate <select class="shuttle-boxes-left">.
The way I am trying to do it that isn't working is simply copying over the ng-options attribute to the select list like so:
var availableList = cElement.find('.shuttle-boxes-left'),
repeater = cAttrs.ngOptions;
availableList.attr('ng-options', repeater);
Here is the fiddle: http://jsfiddle.net/dkrotts/tHTAY/1/
What am I doing wrong?
I suggest you only pass the itemList to the directive (and myModel) and put the ng-options inside your template:
<shuttle-boxes items="itemList" ng-model="myModel"></shuttle-boxes>
Directive:
myApp.directive('shuttleBoxes', function($timeout) {
return {
restrict: 'E',
scope: { items: '=', ngModel: '='},
template: '<div class="shuttle-boxes">' +
'<select multiple="multiple" class="shuttle-boxes-left"
ng-options="item for item in items" ng-model="ngModel"></select>' +
'<button class="shuttle-boxes-btn" type="button">' +
'<i class="icon icon-arrow-right"></i></button>' +
'<button class="shuttle-boxes-btn" type="button">' +
'<i class="icon icon-arrow-left"></i></button>' +
'<select multiple="multiple" class="shuttle-boxes-right"></select>' +
'</div>',
replace: true
}
});
Fiddle.

Resources