Hide the div section using custom directive - angularjs

I have created a custom directive to show the error messages in the page. My directive is
app.directive('errorsection', function () {
return {
restrict: 'EA',
scope: {
errors: '=errors'
},
templateUrl: '..../shared/error-section.html'
};
});
error-section.html
<div ng-show="errors.length>0" class="error">
<div id="{{error.Id}}" ng-class="{'error':error.Type=='Error','alert-info alert-dismissible cssDataTargetDismiss-{{error.Id}} fade in':error.Type=='Info'}"
ng-repeat="error in errors track by $index">
<button ng-if="error.Type=='Info'" type="button" class="close" data-toggle="collapse" data-target=".cssDataTargetDismiss-{{alert.Id}}">×</button>
<p><strong ng-bind-html="error.TypeDescription"></strong><span ng-bind-html="error.Message"></span></p>
</div>
I have used this directive in one of my partial page to show the error messages
<div error-section errors="errorList"></div>
this errorList contains 2 messages . if i click the button, message is collapsed. I want to hide the div if all the error messages collapsed..
error messages is showing in view like below format,
______________
|error1 x|
|error2 x|
_______________
can anyone help how to hide the div?

try
<div ng-show="errors.length>0 && message !== 0">
<div id="{{error.Id}}" ng-class="{'error':error.Type=='Error','alert-info alert-dismissible cssDataTargetDismiss-{{error.Id}} fade in':error.Type=='Info'}"
ng-repeat="error in errors track by $index">
<button ng-click="message -= 1" ng-if="error.Type=='Info'" type="button" class="close" data-toggle="collapse" data-target=".cssDataTargetDismiss-{{alert.Id}}">×</button>
<p><strong ng-bind-html="error.TypeDescription"></strong><span ng-bind-html="error.Message"></span></p>
and in your directive controller take the length of the messages and give it to $scope.message.

Change your directive to use replace instead:
app.directive('errorsection', function () {
return {
restrict : 'EA',
scope : {
errors : '=errors'
},
replace: true, //tell it to replace
templateUrl : '..../shared/error-section.html'
};
});
This will make it so that
<div error-section errors="errorList"></div>
And
<div ng-show="errors.length>0" class="error">
Are the same div like this:
<div error-section errors="errorList error" ng-show="errors.length>0">
...
</div>
As opposed to:
<div error-section errors="errorList">
<div ng-show="errors.length>0" class="error">
...
</div>
</div>

Related

Delete json object from directive

hello I want to delete json in angularjs
for the first time I only use ng-repeat directive
<div ng-repeat="artworkItem in artworksItems | filter: {category:'artworks'}| filter:query" class="">
<p>{{artworkItem.name}}</p>
<button ng-click="remove($index)">delete</button>
</div>
controller
ItemFactory.get().then(function(data) {
$scope.artworksItems = data;
});
$scope.remove= function(index){
$scope.artworksItems.splice(index, 1);
}
it works. Then i try to move it with directive.
so my code will be like this
<div ng-repeat="artworkItem in artworksItems | filter: {category:'artworks'}| filter:query" class="">
<grid-artworks data="artworkItem"></grid-artworks>
</div>
directive.html
<div>
<div class=" col-xs-6 col-sm-4 col-md-3 productThumbnail">
<a href="#/Artworks/{{data.id}}" class="">
<img ng-src="{{data.imgUrl}}" alt="{{data.name}}" class="img-responsive">
</a>
<div class="caption">
<p class="title text-center">{{data.name}}</p>
<p class="text-center">{{data.priceTotal}} {{data.curency}}</p>
<button ng-click="remove($index)">d</button>
</div>
</div>
</div>
directive.js
angular
.module('app.directives.gridViewArtworks',[])
.directive('gridArtworks',function()
{
return{
restrict:'E',
scope:{
data: '='
},
transclude:true,
replace:true,
templateUrl:"templates/directives/gridViewArtworks.html",
controller:function($scope){
console.log($scope.data);
}
};
}
);
controller
ItemFactory.get().then(function(data) {
$scope.artworksItems = data;
});
$scope.remove= function(index){
$scope.artworksItems.splice(index, 1);
}
with directive I can't delete the item. Please help me why can't I delete the data.
Pass a callback to your directive from the controller, which will be triggered from removing the element from the array.
scope:{
data: '=',
onRemove: '&'
},
Then when you call the directive:
<grid-artworks data="artworkItem" on-remove="remove(id)"></grid-artworks>
And inside your directive:
<button ng-click="onRemove({id: data.id})">d</button>
And change your remove function in the controller in order to use the id for removing elements from the array, because it's safer than the $index:
$scope.remove= function(id){
$scope.artworksItems.splice($scope.artworksItems.findIndex(el => el.id === id), 1);
}
You could pass index as an attribute.
<grid-artworks data="artworkItem" index="{{$index}}"></grid-artworks>
You'll need to add it to your directive's scope.
scope: {
index: '#',
// ...
And then you can use it.
<button ng-click="remove(index)">d</button>
Alternatively, you should be able to do remove(data):
var index = $scope.artworksItems.indexOf(data);
$scope.artworksItems.splice(index, 1);

Directive not loading inside ng-repeat with ng-if

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() {

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.

Wrap content using directive and transclude

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

How to get the form data when the form is in a directive in Angular?

I have this this template:
<div class="modal" id="popupModal" tabindex="-1" role="dialog" aria-labelledby="createBuildingLabel" aria-hidden="true">
<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" id="createBuildingLabel">{{ title }}</h4>
</div>
<form data-ng-submit="submit()">
<div class="modal-body" data-ng-transclude>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-ng-click="visible = false">Annuleren</button>
<button type="submit" class="btn btn-primary"><span class="glyphicon glyphicon-save"></span>Maken</button>
</div>
</form>
</div>
</div>
</div>
and here's the directive:
app.directive("modalPopup", [function () {
return {
restrict: 'E',
templateUrl: 'Utils/ModalPopup',
scope: {
title: '#',
onSubmit: '&',
visible: '='
},
transclude: true,
link: function (scope, element, attributes) {
var container = $("#popupModal");
scope.submit = function (newGroup) {
scope.onSubmit(newGroup);
}
scope.hide = function () {
container.modal('hide');
}
scope.show = function () {
container.modal('show');
}
scope.$watch('visible', function (newVal, oldVal) {
if (newVal === true) {
scope.show();
}
else {
scope.hide();
}
})
}
}
}]);
As you can see I have declared my form tag inside the directive and I also use transclude to determine how my form is going to look like. For now I have this:
<modal-popup title="Nieuwe groep aanmaken" data-on-submit="createGroup()" visible="showAddGroupForm">
<div class="row">
<div class="col-md-3">Kopieren van:</div>
<div class="col-md-8">
<select class="form-control" data-ng-model="newGroup.Year">
<option value="">Nieuw jaar</option>
<option data-ng-repeat="year in years" value="{{year.Id}}">{{year.Name}}</option>
</select>
</div>
</div>
<div class="row">
<div class="col-md-3">Naam</div>
<div class="col-md-8">
<input type="text" class="form-control" data-ng-model="newGroup.Name" />
</div>
</div>
</modal-popup>
When the submit button is pressed, I want the data to be available in my controller.
I ques the data isn't available because of the isolated scope, however I'm not sure. What do I need to do to get the data back from the directive into my controller?
PS: I know about angular-ui and angularstrap, but I'm doing this to learn about Angular.
EDIT:
Here's a Fiddle
I think the cause is a misunderstanding about how scopes work (especially with transclusion).
Let's start with this code (from the fiddle):
<div ng-controller="MyCtrl">
<my-popup on-submit="formSubmitted(model)">
<input type="text" ng-model="model.Name"/>
</my-popup>
</div>
Since <my-popup> transcludes its content, the scope above is that of MyCtrl, even in the content of the directive. By content I mean the <input>, NOT the directive template, i.e. the <div><form ... code.
Therefore it is implied that model (as used in ng-model="model.Name") is a property of the scope of MyCtrl, as is formSubmitted(). Since both are members of the same scope, you do not need to pass the model as argument; you could just do:
(in the template:)
<my-popup on-submit="formSubmitted()"><!-- no `model` argument -->
(the controller:)
function MyCtrl($scope) {
// I like declaring $scope members explicitly,
// though it can work without it (charlietfl comments)
$scope.model = {};
$scope.submittedValue = null;
$scope.formSubmitted = function() {
// another bug was here; `model` is always a member of the `$scope`
// object, not a local var
$scope.submittedValue = $scope.model.Name;
}
}
Another bug is in the directive code:
link: function(scope, element, attributes){
scope.submit = function(){
scope.onSubmit({model: model});
}
}
The variable model (not the name model:) is undefined! It is a property of the parent scope, so you would have a chance if the scope was not isolated. With the isolated scope of the directive, it may work with an awful workaround that I am not even considering to write :)
Luckily, you do not need the directive to know about things happening in the external scope. The directive has one function, to display the form and the submit button and invoke a callback when the submit button is clicked. So the following is not only enough for this example, but also conceptually correct (the directive does not care what is happenning outside it):
link: function(scope, element, attributes){
scope.submit = function(){
scope.onSubmit();
}
}
See the fiddle: http://jsfiddle.net/PRnYg/
By the way: You are using Angular v1.0.1. This is WAAAAY too old, seriously consider upgrading!!! If you do upgrade, add the closing </div> to the template: <div ng-transclude></div>.

Resources