AngularJS directive binding issue - angularjs

I have created an AngularJS directive on one of the pages and it's not rendering. I don't get any errors either. Following is the directive template and directive binding code. Appreciate if someone can help.
directive.js
var cardCollapsiblePanelModule = angular.module('cardCollapsiblePanelModule',[]);
cardCollapsiblePanelModule.directive('cardCollapsiblePanel', function() {
return {
restrict: 'A',
templateUrl: 'scripts/virtualserver/virtualserverfeatures/monitoringprobes/views/directive- templates/monitoring-probe-card-collapsible-panel-template.html',
scope: {
cardName: '#cardName'
},
controller: function ($scope, $element, $attrs) {
// update dependent scope.
},
link: function (scope, $element, $attrs) {}
}
});
directive HTML:
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title clearfix" data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
<div class="pull-left">{{ cardName }}</div>
<div class="pull-right" ><span class="iconSmall iconExpand"></span></div>
</h4>
</div>
<div id="collapseOne" class="panel-collapse collapse">
<div class="panel-body">
<!-- load the capture card settings directive here -->
</div>
</div>
</div>
directive is being used as follows:
<div class="panel-group" id="accordion">
<!-- accordion directive for collapsible panel -->
<div card-collapsible-panel card-index="{{$index}}" ng-repeat="card in monitoringProbeCards">
</div>
</div>
My objective is to bind the headers of collapsible panels with the card name through the directive. Can someone point out what's wrong with the code?
My REST service response is as follows:
[{"id":1,"cardName":"Card 0 : PIST-16-TDM-PCI-Basic-32 - SN: GPER190201064","interfaceType":"TDM","probeServerId":2},{"id":2,"cardName":"Card 1 : PIST-16-TDM-PCI-Basic-32 - SN: GPER190201065","interfaceType":"TDM","probeServerId":2}]

Try this...
<div class="panel-group" id="accordion">
<!-- accordion directive for collapsible panel -->
<div ng-repeat="card in monitoringProbeCards">
<div card-collapsible-panel="{{$index}}"></div>
</div>
</div>

I think you need to add card-name to the directive Div:
<div card-collapsible-panel card-index="{{$index}}" ng-repeat="card in monitoringProbeCards" card-name="{{card.cardName}}" >
Binding to {{cardName}} from the directive HTML, binds to the cardName field on the isolated scope which in turn via the # sign followed by cardName binds to the card-name attribute on the directive using one-way data binding which means that the value of that attribute needs to be evaluated by Angular, hence the {{card.cardName}}.

Related

Automatic scrolling with angularJs

I have a list of items, inside a div, with a ng-repeat angular directive. And I need this list, to use an automatic scrolling, it's a DEMO (it's, use the jquery super-treadmill). How can I do this with angular js (version 1.6)?
<div class="panel-body">
<div ng-repeat="model in collection">
<h1>{{model.name}}</h1>
<p>{{model.description}}</p>
</div>
</div>
you can do it with simple directive
app.directive('startTreadmill', function(){
return {
link: function(scope, element, attr){
$(element).startTreadmill({ direction: "down"});
}
}
})
<div class="panel-body" start-treadmill>
<div ng-repeat="model in collection">
<h1>{{model.name}}</h1>
<p>{{model.description}}</p>
</div>
</div>

Angular toggle class to parent element

For angular I'm using a Directive to Toggle Class:
app.directive('toggleClass', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function() {
element.toggleClass(attrs.toggleClass);
});
}
};
});
And the HTML I have multiple times:
<div class="tab" toggle-class="open">
<div class="title">
<p>Tab title</p>
</div>
<div class="content">
<!-- This element hidden by default, needs toggle -->
<p>Foobar</p>
</div>
</div>
It works, but when I click somewhere in the .content-element, it also toggles. But I want it to stay active. Not toggle-ing back to the close-state.
Is there an easy way to let it work like this:
- click on .title
- toggle .content (by adding .open to the .tab-element.
Added .parent()
app.directive('toggleClass', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('click', function() {
element.parent().toggleClass(attrs.toggleClass);
});
}
};
});
And toggle-class to the title element.
<div class="tab">
<div class="title" toggle-class="open">
<p>Tab title</p>
</div>
<div class="content">
<!-- This element hidden by default, needs toggle -->
<p>Foobar</p>
</div>
</div>
I just consider that you don't need a custom directive to do this kind of things.
Here is two exemples, first one with the angular way to toggleClass, second one in a global angular way.
Both will meet your needs covered by this directive.
First One :
<div ng-repeat="aTab in [{},{},{},{},{}]" class="tab" ng-class="{'open':isOpen}">
<div class="title" ng-click="isOpen = !isOpen">
<p>Tab title</p>
</div>
<div class="content">
<!-- This element hidden by default, needs toggle -->
<p>Foobar</p>
</div>
</div>
with this CSS
.content {
display:none;
}
.open .content {
display:block;
}
Second one :
<div ng-repeat="aTab in [{},{},{},{},{}]" class="tab">
<div class="title" ng-click="aTab.show = !aTab.show">
<p>Tab title</p>
</div>
<div class="content2" ng-show="aTab.show">
<!-- This element hidden by default, needs toggle -->
<p>Foobar</p>
</div>
</div>
You can see theses exemples in this plunker
Hope it helped
EDIT : Updated the exemples and plunker to show how it works with an ng-repeat

angular does not load my directive

I newly start to use angular.but I have some problem to loading my directive.
I want to load my directive as soon as page loaded.
where I load data-show directive
<div class="row">
<div class="col-md-12">
<article class="row" ng-controller="DataCtrl">
<input type="button" ng-click="getDataList()" >
<h1>Some Content Here</h1>
<ul id="home" bread-crumbs></ul>
<ul class="thumbnails">
<li ng-repeat="data in list" class="col-md-5">
<show-data data="data"/>
</li>
</ul>
</article>
</div>
</div>
showData directive:
app.directive('showData', function () {
return{
restrict: 'E',
replace:true,
templateUrl: 'views/directives/datas.directive.html',
scope: {
data: "="
},
controller:'DataCtrl'
}
})
and template I used in:
<div class="well hoverwell">
<div class="row">
<h2 class="col-md-4">{{data.name}}</h2>
</div>
<div class="row">
<span class="col-md-1">Code:</span>
<span class="col-md-1">{{data.id}}</span>
</div>
<div class="row">
<span class="col-md-1">accountability:</span>
<span class="col-md-1">{{data.parent}}</span>
</div>
<div class="row">
<span class="col-md-1"> :</span>
<span class="col-md-1">{{data.definition}}</span>
</div>
</div>
and my controller
'use strict';
angular.module('app')
.controller('DataCtrl', function ($scope, DataService, $log) {
$scope.getDataList = function () {
var list = DataService.getDataList(1);
list.then(
function (result) {
$log.info(result);
$scope.dataList = result;
}, function (status) {
$log.error(status)
$scope.msg = "error " + status + " has been occur,please report to admin ";
});
};
});
and when I run my app it does not work .
when I watch it in chorome development tools my directive is comment
what is my problem.How can I call this directive as soon as page load.
thx
As you already noticed, you see empty list because your dataList in ng-repeat is not filled yet.
But you have some errors in your code:
First of all - you should never use one controller twice. So you need to create separate controller for your directive.
replace directive parameter is deprecated, better not to use it.
In your DataCtrl you set the dataList variable: $scope.dataList = result;, but in HTML you refer to list variable: <li ng-repeat="data in list" class="col-md-5">.
Maybe that example will help you to figure out with your code.

angular js - ng-hide/ng-show API not working properly

Here i trying to implement application in angular js. I have an minimize/maximize button for all child element and seprate minimize/maximize button to inside child element.
But when i click toggle minimize its minimize all all child element.
Problem is when i click toggleonce it also minimize all child element.
var dashboard = angular.module("dashboard",['ui.bootstrap']);
dashboard.controller('dash-control', ['$scope', function($scope) {
$scope.isHidden = false;
$scope.toggle = function(){
$scope.isHidden = !$scope.isHidden;
};
$scope.toggleonce= function()
{
if( this.isHidden === true)
this.isHidden = false;
else
this.isHidden = true;
};
}]);
VIEW:
<div class="contentpanel" ng-app="dashboard" ng-controller="dash-control as ctrl">
<button class="btn btn-white" type="button" ng-click="toggle()">
<i class="fa fa-minus-square"></i>
</button>
<div>
<a href="" class="tooltips" ng-click="toggleonce()" title="Minimize Panel">
<i class="fa fa-minus"></i>
</a>
<div class="row tinychart" ng-show="isHidden">Contenr Heading 1</div>
<div class="row tinychart" ng-hide="isHidden">Content Description 1</div>
</div>
<div>
<a href="" class="tooltips" ng-click="toggleonce()" title="Minimize Panel">
<i class="fa fa-minus"></i>
</a>
<div class="row tinychart" ng-show="isHidden">Contenr Heading 2</div>
<div class="row tinychart" ng-hide="isHidden">Content Description 1</div>
</div>
......
.....
.....
</div>
The variable $scope.isHidden is a controller level variable and by clicking toggleonce() you are changing the variable to true through out the page(since both the 'minimize panels' are in the scope of the controller. Thereby any ng-hide for isHidden will be hidden and thereby it is causing the global 'minimise'.
You have two options:
1) use separate variables for each Minimize panel and toggle the values of that variable when you click on the corresponding function. Also write the Panel level 'ng-hide's for its own variable.
2) write a isolated scope directive for all Minizable panels. And isolate its scope from the Controller. Now write a toggleonce function in the directive which changes the value of the Hidden variable within the directive's scope. You must use the following syntax while writing the directive:
.directive('minimizePanel', function() {
return {
scope: true,
};
You can watch this video for more inputs.

AngularJS: Access models using dynamic names in template

I have a template with a lot of what is essentially duplicate code. I'd like to use a directive to include a partial template which I can manipulate for each "block" of duplicate code.
The template currently looks something like this:
<div class="column book">
<div class="header">
<input type="text" id="book_query" ng-model="book_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="book in books | filter:book_query">
{{book.name}}
</div>
</div>
</div>
....
<div class="column game">
<div class="header">
<input type="text" id="game_query" ng-model="game_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="game in games | filter:game_query">
{{game.name}}
</div>
</div>
</div>
....
And the controller just gets the data and adds it to the scope e.g.
$scope.books = data.books;
$scope.games = data.games;
What I started doing was using a directive which takes in an argument (e.g. book, game etc) so I then knew which model(s) to use. The problem I have is how to use the argument to access the model in the template? The directive itself is, currently, very simple:
<div item-column item="book"></div>
<div item-column item="game"></div>
app.directive('itemColumn', function() {
return {
scope: {
item: '#'
},
replace: true,
templateUrl: 'item_column.html'
};
});
In item_column.html, I was hoping I could just substitute the item argument, which works fine for displaying the value of the arg but not for replacing where 'book' or 'game' is used for the models e.g.
<div class="column {{item}}">
<div class="header">
<input type="text" id="{{item}}_query" ng-model="{{item}}_query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in ??? | filter:{{item}}_query">
{{item.name}}
</div>
</div>
</div>
Can someone show me the best way of doing this? I don't doubt I'm going the complete wrong way about it!
EDIT: The original issue above is now pretty much fully solved using JoseM's answer below. The one outstanding issue is the on-click functions on each element no longer firing the parent scope from within the isolated scope.
My controller is laid out like so:
app.controller('ItemsCtrl', ['$scope', '$http', 'CONFIG', function($scope, $http, CONFIG) {
var items = ['books', 'games'];
items.forEach(function(item) {
$scope[item] = [];
$scope['selected_'+item] = null;
})
$scope.getItem = function(item) {
$http.get('?action=get_item&id='+item.id+'&type='+item.type)
.success(function(data) {
// update model
})
.error(function(data, status) {
// do something
});
}
}]);
$scope.getItem is no longer accessible when clicking on the item in the view, which looks similar to the following after implementing JoseM's answer:
<div class="row" ng-repeat="item in array | filter:query">
<div class="text" ng-click="getItem(item)">
{{item.name}}
</div>
</div>
Is there a simple way of making the parent scope functions available from within the isolated scope? Or is there a better place for these functions? Apologies for (what I feel are) the very basic questions - I'm still trying to get my head around Angular!
One way to accomplish what you want is by using a child scope in your directive and then doing your own "linking" of the parent scope variables using a watch on the parent scope value.
in your directive:
app.directive('itemColumn', function() {
return {
scope: true,
templateUrl: 'item_column.html',
link: function(scope,elem,attrs) {
var varName = scope.varName = attrs.item;
var parScope = scope.$parent;
parScope.$watch(varName + 's', function(newVal){
scope.theArray = newVal;
});
parScope.$watch(varName + '_query', function(newVal){
scope.theQuery = newVal;
});
}
};
});
in your template:
<div class="column {{varName}}">
<div class="header">
<input type="text" ng-attr-id="{{varName}}_query" ng-model="theQuery.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in theArray | filter:theQuery">
{{item.name}}
</div>
</div>
</div>
If you want to use an isolated scope, you could it, but then you would have to supply at least 3 attributes if you are using the same properties as above. I personally believe that using an isolated scope is a better way of doing it. See below how the isolated version is simpler:
isolated version of directive
app.directive('itemColumn2', function() {
return {
scope: {
label: '#',
array: '=',
query: '='
},
templateUrl: 'item_column2.html'
};
});
isolated version of template
<div class="column {{label}}">
<div class="header">
<input type="text" ng-attr-id="{{label}}_query" ng-model="query.name" />
</div>
<div class="content">
<div class="row" ng-repeat="item in array | filter:query">
{{item.name}}
</div>
</div>
</div>
usage
<div item-column2 label="book" array="books" query="book_query"></div>
<div item-column2 label="game" array="games" query="game_query"></div>
And finally here is a sample plunker: http://plnkr.co/edit/OyEHR4ZhzYKvs4jeDfjD?p=preview

Resources