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>
Related
I'm creating a Masonry layout populated with images and videos and since the images-loaded directive doesn't work I'm trying to come up with a quick work around. (https://github.com/passy/angular-masonry/issues/116)
The problem I have is the link function is never fires. I'm wondering if it has something to do with ng-if's being encapsulated by an ng-repeat because according to this plunkr (http://jsfiddle.net/q05gret0/) the link function should run whenever ng-if evaluates to true
<div style="margin:auto;" images-loaded="false"
masonry="{isFitWidth: true}">
<div class="masonry-brick media-block"
ng-repeat="mediaItem in media">
<div ng-if="mediaItem.type === 'image/jpeg' || mediaItem.type === 'image/png'">
<img alt="image" class="fill-width" ng-src="{{MEDIA_URL + mediaItem.urlThumbnail}}" data-loaded>
</div>
<div ng-if="mediaItem.type === 'video/mp4'">
<video autoplay="true" loop="loop" muted="muted" data-loaded>
<div trust-url url="mediaItem.url"></div>
</video>
</div>
<div class="media-info container-fluid">
<div class="col-xs-9 no-padding">
<h5 class="media-title">{{mediaItem.name}}</h5>
</div>
<div class="col-xs-3 no-padding">
<button class="btn btn-sm btn-danger" ng-click="deleteMedia(mediaItem)"><i
class="fa fa-trash-o"></i></button>
</div>
</div>
</div>
</div>
And the directive in question:
.directive('dataLoaded', function dataLoaded() {
return {
restrict: 'A',
link: function (scope, iElement) {
console.log("linked!");
iElement.bind('load', function() {
scope.$broadcast("masonry.reload");
});
},
};
})
You are using the wrong directive name
<video autoplay="true" loop="loop" muted="muted" data-loaded>
"data-loaded" looks for a directive with a name "loaded". So you need rename directive to "loaded" or to change the attribute to "data-data-loaded". I'd prefer to rename the directive
Please replace this line:
.directive('dataLoaded', function dataLoaded() {
with that line:
.directive('loaded', function dataLoaded() {
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
I would like to surround and input with a wrapper which contains multiple divs. I would want the input to be placed inside of the div called "my-content". I'm using a directive to achieve this, but it's not being placed inside the wrapper.
These are the templates I tried:
This doesn't work
<div class="wrapper" >
<div class="left-side" > </div>
<div class="middle">
<div class="top-side"> </div>
<div class="my-content" ng-transclude ></div>
<div class="bottom-side"> </div>
</div>
<div class="right-side"> </div>
</div>
But this works
<div class="wrapper" >
<div class="left-side" > </div>
<div class="middle">
<div class="top-side"> </div>
<input class="my-content" ng-transclude />
<div class="bottom-side"> </div>
</div>
<div class="right-side"> </div>
</div>
Directive is defined as such:
app.directive('wrapMe', function(){
return {
restrict: "A",
templateUrl: 'template.html',
transclude: true,
replace: true
};
});
So to reiterate, I would like whatever has the wrap-me directive to be placed inside the div with 'my-content' class and ng-transclude. Am I missing something here?
Plunker link: http://plnkr.co/edit/oQtWNCBBuc61bRwzDjHP?p=preview
You're almost there. Just change transclude option to element and you're done. Basically you want both the input element and its contents to be transcluded. The previous option (transclude: true) only transcludes the contents, which is empty, that's why it didn't work.
app.directive('wrapMe', function(){
return {
restrict: "A",
templateUrl: 'template.html',
transclude: 'element',
replace: true
};
});
Updated plunkr: http://plnkr.co/edit/IX0ELKR4wKOPtt2vO6FB?p=preview
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
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}}.