Let say we have the following directive:
app.directive('testList', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
//do stuff
}
}
});
I would like to call this directive from multiple element in html
<button test-list-add></button>
<table test-list="listObject">
<tr ng-repeat="list in testList">
<td test-list-click>list.item</td>
</tr>
</table>
is it possible to get into the link function for each attribute starting with test-list (test-list-add, test-list, test-list-click)?
Thank you
You want to pass attributes to your directive and doing some action, depending on the attribute:
app.directive('testList', function () {
return {
restrict: 'A',
scope: {
'add': '#', // Text
'click': '&' // function
},
link: function (scope, element, attrs) {
// scope.add - your Text you passed
// scope.click(); - calls your function you passed
}
}
});
<button test-list add="test"></button>
<table test-list="listObject">
<tr ng-repeat="list in testList">
<td test-list click="myFunc()">list.item</td>
</tr>
</table>
You can't repeat a directive (what you obvis trying to do).
If you want to make multiple suffix for a directive, you have to declare them one by one:
app.directive('testListAdd', function () {...});
app.directive('testListclick', function () {...});
<test-list-add></test-list-add>
<test-listclick></test-listclick>
Related
I want to write a directive to for a table TBODY to show some text when it is empty. I want to achieve this by writing a directive that detects if the table's TBODY has any child TR, if not then show some text.
I do not wish to use ng-if="model.entries.length == 0" because I might have a TR in there for creating new entry that won't belong to entries.
The directive I wrote currently only works one time because it only runs once. When entries changes the directive won't run again and therefore the empty text is still showing
baseModule.directive('emptyTbody', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
if (element.find('tr').length == 0) {
element.addClass('empty');
} else {
element.removeClass('empty');
}
}
}
});
Is it possible to write a directive that runs when scope changes like regular angular behavior? Or if this cannot be achieved through a directive, is there any other ways to achieve this?
Here is the Html
<tbody empty-tbody>
<tr ng-if="isCreating()">
<td>
<input ng-model="creatingItem.Name"/>
</td>
</tr>
<tr ng-repeat="item in model.entries" >
<td>
<input ng-model="item.Name"/>
</td>
</tr>
</tbody>
Create a isolate scope and put watch there
Like this
baseModule.directive('emptyTbody', function() {
return {
restrict: 'A',
scope: {
source: '='
},
link: function(scope, element, attrs) {
scope.$watch("source", function(nv) {
if (nv) {
if (nv.length == 0)
element.addClass('empty');
else
element.removeClass('empty');
} else
element.addClass('empty');
});
}
}
});
HTML
<tbody empty-tbody source="model.leps">
EDIT
If you wanna to use only from element .
You can use anonymous function to watch.
Try like this
baseModule.directive('emptyTbody', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$watch(function() {
return element.find('tr').length;
}, function(nv) {
if(nv){
console.log("Table has data")
}
else
console.log("Table has no data");
});
}
}
});
JSFIDDLE
The template that loads content("html/script template") for each cell:
<td class="tableColumnsDocs" ng-repeat="attobj in columns track by $index" >
<div ng-init="values = dbo.get4(attobj.key); key = attobj.key; template = attobj.template || getAttributeTemplate(dbo.clazz + attobj.key);">
<div plain-template="template">
</div>
</div>
</td>
I need the directive to access the value "template" from its directive "plain-template"
Directive:
app.directive('plainTemplate', function($parse) {
return {
templateUrl: 'testTemplate',
function (scope, element, attrs) {
console.log($parse(attrs.plainTemplate));
}
};
});
You can use something like
app.directive('plainTemplate', function($parse) {
return {
templateUrl: 'testTemplate',
scope: {
plainTemplate:"="
},
link: function (scope, element, attrs) {
console.log(scope.plainTemplate));
}
};
});
and when you call it in html your variable should be like
<plain-template test-template="anything"> </plain-template>
this is isolated scope. You can see more at https://docs.angularjs.org/guide/directive
Where is the filtered collection after filtered value in smart table.
the table is bound with rowCollection.
<table st-safe-src="rowCollection" st-table="displayed" class="table table-bordered">
and i have used a search filter:
<input type="text" id="regionFilter" st-search="region" />
after the result are filtered i still see all records in rowCollection
You can create a directive to access the get the filtered Collection. For example:
HTML:
<table
st-table="displayedCollection"
st-safe-src="rowCollection"
on-filter="onFilter">
Javascript:
//
// Create a directive
//
angular.module("smart-table").directive('onFilter', function () {
return {
require: '^stTable',
scope: {
onFilter: '='
},
link: function (scope, element, attr, ctrl) {
scope.$watch(function () {
return ctrl.tableState().search;
}, function (newValue, oldValue) {
scope.onFilter(ctrl);
}, true);
}
};
});
//
// In your controller
//
$scope.onFilter = function (stCtrl) {
var filtered = stCtrl.getFilteredCollection();
}
I wrote a directive to check for double values in a data column:
The markup
<table>
<tr data-ng-repeat-start="rowItem in vm.model.data" ...>
<td>
<input type="text" data-ng-model="rowItem.ID" data-unique-column="vm.model.data" />
</td>
...
</tr>
</table>
and the directive
(function () {
'use strict';
angular.module('app').directive('uniqueColumn', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
element.on('keyup blur', function () {
scope.$eval(attrs.uniqueColumn).forEach(function (item) {
// validation logic
});
});
}
};
});
})();
Everything works fine but I asked myself if there was a solution to access the data of my repeater, i.e. vm.model.data, without passing an argument to the directive?
Because you didn't isolate the scope, you can read javascript's prototypal inheritance. You can perhaps access a method from the child that will then lookup to the parent's. And perhaps use the $index as the parameter.
Why not use another directive to define the unique-column's model and add it as a dependency on the unique-column directive, like this:
unique-column-model directive:
app.directive('uniqueColumnModel', function() {
return {
restrict: 'A',
controller: function($scope) {
// add more logic here if necessary
},
link: function (scope, element, attrs, ngModel) {
// save the value of the uniqueColumnModel as a private var in the scope
scope.$uniqueColumnModel = scope.$eval(attrs.uniqueColumnModel);
}
};
});
unique-column directive:
app.directive('uniqueColumn', function() {
return {
restrict: 'A',
// set the uniqueColumnModel directive as a dependency (^ is to search on parents)
require: ['ngModel', '^uniqueColumnModel'],
link: function (scope, element, attrs, ngModel) {
element.on('keyup blur', function () {
// use the private $uniqueColumnModel var that was
// previously saved on the scope
angular.forEach(scope.$uniqueColumnModel, function(item) {
// validation logic
});
});
}
};
});
And on the HTML:
<tr ng-repeat="item in model.items" unique-column-model="model.items">
<td>
<input type="text" ng-model="item.id" unique-column />
</td>
</tr>
Check this plunker.
There's still room for improvement but the idea is there...
I have a table where the rows are repeated via ng-repeat.
I am trying to create a template that generates columns <td> for each row <tr>
app.directive("customtd", function(){
return {
restrict: 'E',
template: "<td>{{position.Name}}</td><td>{{position.Code}}</td>",
replace: true,
scope: {
position: '='
}
}
});
<table>
<tr ng-repeat="p in positions">
<customtd position="p"></customtd>
</tr>
</table>
The issue is my custom td template is not rendered at all.
Here I intend to replace <customtd> with n number of <td>s - which will be decided based on number of properties on my data object, but at the moment I am just trying to get a simple directive working that will output two columns.
MYPLUNKER : shows an instance of this issue and the directive code.
As pointed out in comments the template of a directive should have single root element. So I would suggest you to move the tr element to the template of the directive, like this: http://plnkr.co/edit/YjLEDSGVipuKTqC2i4Ng?p=preview
As Pavlo wrote, you can move the tr element to the template for the directive. Another option is to use a td element and directive that replaces your td with the template that you want to use.
<table>
<tr ng-repeat="p in positions">
<td replace-me template="mytemplate.html" position="p"></td>
</tr>
</table>
Directive replaceMe
.directive("replaceMe", ["$compile", '$http', '$templateCache', function ($compile, $http, $templateCache) {
return {
restrict: 'A',
scope: {
position: "="
},
link: function (scope, element, attrs) {
function getTemplate(template) {
$http.get(template, {cache: $templateCache}).success(function (templateContent) {
element.replaceWith($compile(templateContent)(scope));
});
}
scope.$watch(attrs.template, function () {
if (attrs.template) {
getTemplate(attrs.template);
}
});
}
}
}]);
mytemplate.html
<td>{{position.Name}}</td>
<td>{{position.Code}}</td>
<td another-my-directive></td>
plunker