This is the problem: I want to sort a table by clicking on a table header. To avoid repeating code every , I have made a directive. The table headers show up nicely but I cannot find a way to make them sortable.
This is (part of) my HTML:
<div class="table-responsive" >
<table class="table table-striped" >
<thead>
<tr>
<th> </th>
<th><t-header name="vnaam" hoofd="voornaam" ></t-header></th>
<th><t-header name="anaam" hoofd="achternaam"></t-header></th>
</tr>
</thead>
<tbody>
<tr dir-paginate="cursist in homeCtrl.ckaart | orderBy: homeCtrl.sortKey:!homeCtrl.reverse" current-page="homeCtrl.currentPage">
<td><a ng-click="homeCtrl.gotoDetail(cursist.id)"><span ng-class="cursist.keuzemotivatie.length || cursist.leerdoelen.length ? 'infosign-true' : 'infosign-false'" class="fa fa-info-circle infosign"></span></a></td>
<td>{{cursist.vnaam}}</td>
<td>{{cursist.anaam}}</td>
</tr>
</tbody>
My directive:
.directive('tHeader', function(){
return {
restrict: 'EA',
scope: {
name: "#",
hoofd: "#"
},
templateUrl: 'templates/theader.html',
controllerAs: 'vm',
bindToController: true,
controller: function() {
var vm = this;
vm.sortKey = '-instrument';
// sort t.b.v. table sorting
vm.sort = function(keyname) {
// alert(keyname);
vm.sortKey = keyname;
vm.reverse = !vm.reverse;
console.log(vm.sortKey);
}
}
}
})
And the template belonging to the directive:
<div ng-click="vm.sort(vm.name)">{{vm.hoofd}}
<span ng-show="vm.sortKey === vm.name" ng-class="{ 'fa fa-chevron-up':vm.reverse, 'fa fa-chevron-down':!vm.reverse }"></span>
</div>
It seems to me that the 'vm.sortKey' parameter as well as the 'vm.reverse' parameter are not being passed into the HTML.
Anyone an idea? What mistake do I make?
Related
I am trying to create a small angular and php app. I want to display table and be able to edit it by displaying textbox in place of the old text on the click of a button. Can you please help me with the same. Thanks in advance
This is my controller
angular.module('directiveModule').controller('HomeController',['fetchServerData',function (fetchServerData) {
var ctrl = this;
ctrl.stateVal = false;
ctrl.getTableData = function () {
fetchServerData.getStudentsData()
.then(
function (response) {
ctrl.tableData =response.data;
},
function (response) {
console.log(response);
}
)
};
ctrl.init = function () {
ctrl.getTableData();
};
ctrl.init();
ctrl.editPrice = function () {
ctrl.stateVal = true;
};
}]);
This is the controller html
<table class="table table-striped">
<thead>
<tr>
<th>Flowers</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody ng-repeat="flower in home.tableData">
<tr>
<td>{{flower.name}}</td>
<td click-to-edit price="flower.price" stateVal="home.stateVal"></td>
<td><button><span class="glyphicon glyphicon-pencil" title="Edit Price" ng-click="home.editPrice()"></span></button></td>
</tr>
</tbody>
</table>
I am using a directive to implement the replacement
angular.module('directiveModule').directive('clickToEdit',[function () {
return{
scope: {
price : '=',
stateVal : '='
},
templateUrl: 'templates/directiveTemplates/clickToEdit.html',
restrict : 'EA',
link: function (scope, elem, attrs) {
scope.edit = scope.stateVal;
}
}
}]);
directive html
<div>
<span ng-hide="edit">
{{price}}
</span>
<div ng-show="edit">
<input class="inputText" type="text"/>
<div class="glyphicon glyphicon-ok" ng-click="save()"></div>
<div class="glyphicon glyphicon-remove" ng-click="cancel()"></div>
</div>
</div>
So this is my code, but the textbox does not appear on ng-click of the edit-pencil
Finally this is my json response
[{"name":"Lilies","price":200},{"name":"Carnations","price":200},{"name":"Roses","price":200},{"name":"Orchids","price":200},{"name":"Tulips","price":200}]
Please help me make it work
The following observations need to be corrected in your code
The attribute name stateVal should be state-val
a) You should keep a watch on your scope.stateVal if you want to scope.edit to be effected when click happened.
Or
b) You can use ng-hide="stateVal" in clickToEdit.html instead of ng-hide="edit".
The click event of the button should be called with flower variable inorder to isolate each edit of the row
<!-- HTML -->
<button ng-click="home.editPrice(flower)"><span class="glyphicon glyphicon-pencil" title="Edit Price">Edit</span></button>
/* Controller */
ctrl.editPrice = function (flower) {
flower.stateVal = true;
};
You can find the working code with above mentioned changes made in the following URL
Click here
Or
https://plnkr.co/edit/ve6AAewoKAtuUHWczaDG?p=preview
You have error in :
<td click-to-edit price="flower.price" stateVal="home.stateVal"></td>
property must by lowercase letters with - (snake case):
<td click-to-edit price="flower.price" state-val="home.stateVal"></td>
stateVal - > state-val
I have a table in a template I want to populate with different data. My approach is using directives in Angular. I managed to make a template out of my table but I have no idea how to apply the value for the ng-repeat attribute from my html.
Here's a part of my index.html
<div id='unannounced' kc-item-table>
</div>
And here's a part of my template
<table class='table'>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in changableItemList'>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
</tr>
</tbody>
</table>
Heres my directive
app.directive('kcItemTable', function() {
return {
restrict: 'E',
templateUrl: 'scripts/controllers/itemTableTemplate.html'
}
})
So in order to reuse the template I want to be able to change the
ng-repeat='item in itemList'
But I have no idea how to append it to right element.
Here is the simple explaination with your code./
Your html template -
<table class='table'>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='item in changableItemList'>
<td>{{item.name}}</td>
<td>{{item.description}}</td>
</tr>
</tbody>
</table>
Directive-With an isolate Scope
app.directive('kcItemTable', function() {
return {
restrict: 'E',
scope :{
itemList :'='
},
templateUrl: 'scripts/controllers/itemTableTemplate.html'
}
})
You can use directive with different list --
<div id='unannounced' kc-item-table item-list='ItemList1'>
</div>
<div id='unannounced' kc-item-table item-list='ItemList2'>
</div>
What you are trying to do is a very basic feature of AngularJS: data-binding to directives.
Check out the documentation about directives: https://docs.angularjs.org/guide/directive
Here is a very basic example forked from the above docs:
Main template:
<div my-customer name="naomi"></div>
<div my-customer name="boby"></div>
Directive:
.directive('myCustomer', function() {
return {
scope: {
name: "#"
},
template: 'Name: {{name}}'
};
});
http://plnkr.co/edit/r9tIzwxCFyEyAU3NX0G1?p=preview
To clarify, what you need in your case is a "scope" property on your directive. You will be able to pass the scope values through the DOM element attributes.
Thats easy just add this to your div where you add your attribute directive.
<div ng-controller="YourCustomController" id='unannounced' kc-item-table>
</div>
then in YourCustomController you would put a $scope property called.
$scope.changableItemList;
Or if you want multiple of these directives on the same page you can work with an isolated scope and do :
<div id='unannounced' kc-item-table customList='customList2'/>
<div id='unannounced' kc-item-table customList='customList1'/>
and in your directive do:
//you will need a controller above this which has $scope.customList declared
app.directive('kcItemTable', function() {
return {
restrict: 'E',
scope :{
customList :'=' //isolated scope with customList passed in
},
templateUrl: 'scripts/controllers/itemTableTemplate.html'
}
})
TL;DR version: I'm trying to write a directive to show various objects in a table, and add an edit / delete button at the end of the table rows.
The example entity will be ProjectType, so:
project-type.controller.js
// determines which attributes we want to show in the table
$scope.attr = [
'computerName',
'shortName',
'longName'
];
// puts the current projectType object to the form
$scope.edit = function(projectType) {
$scope.projectType = projectType;
$scope.computerName = projectType.computerName;
$scope.isEdit = true;
};
// shows a delete modal window
$scope.deleteConfirm = function (projectType) {
Modal.confirm.deleteModal('Project type', projectType.computerName, function () {
Message.createMessage('project-type.message.delete.success', { projectType: projectType.computerName }, { type: 'warning', timeout: 4000 });
$scope.remove(projectType);
})();
};
project-type.html
<!-- show table with directive -->
<entity-table object="projectTypes" entity="'project-type'" attr="attr"></entity-table>
<!-- show table without directive -->
<table class="table table-responsive">
<thead>
<tr>
<th>{{ 'project-type.create.label.computerName' | translate }}</th>
<th>{{ 'project-type.create.label.shortName' | translate }}</th>
<th>{{ 'project-type.create.label.longName' | translate }}</th>
<th>{{ 'common.operations' | translate }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="projectType in projectTypes">
<td><strong>{{ projectType.computerName }}</strong></td>
<td>{{ projectType.shortName }}</td>
<td>{{ projectType.longName }}</td>
<td>
<a ng-click="edit(projectType)" class="pencil"><span class="glyphicon glyphicon-pencil"></span></a>
<a ng-click="deleteConfirm(projectType)" class="trash"><span class="glyphicon glyphicon-trash"></span></a>
</td>
</tr>
</tbody>
</table>
entity-table.directive.js
angular.module('unioffice-centralApp')
.directive('entityTable', function () {
return {
restrict: 'E',
replace: true,
transclude : true,
templateUrl: '/components/directives/entity-table/entity-table.html',
scope: {
object: '=',
entity: '=',
attr: '='
},
link: function (scope, element, attrs, controllers, transclude) {
console.log(scope);
}
};
});
entity-table.html
<div>
<table class="table table-responsive">
<thead>
<tr>
<th ng-repeat="att in attr">{{ (entity + ".table.label." + att) | translate }}</th>
<th ng-repeat-end translate>common.operations</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in object">
<td ng-repeat="att in attr">{{ obj[att] }}</td>
<td ng-repeat-end>
<a ng-click="edit(obj)" class="pencil"><span class="glyphicon glyphicon-pencil"></span></a>
<a ng-click="deleteConfirm(obj)" class="trash"><span class="glyphicon glyphicon-trash"></span></a>
</td>
</tr>
</tbody>
</table>
(there is a /div at the end of the entity-table.html, stackoverflow seems to kill it)
So the question is: how do I pass the edit() and deleteConfirm() functions to the directive to make them work?
In this picture you can see the two tables are the same, but the buttons in the first one obviously won't do anything at this point: (also I know the second one has bold first column, it's ok, that's not the point now)
Passing/binding the functions from the controller to the directive is done in the same manner as binding an object = or a string # with the difference being how it's referenced in the directive
Pass in the functions as attributes on the directive as shown below ..
<entity-table object="projectTypes" entity="'project-type'" on-delete="deleteConfirm" on-edit="edit" attr="attr"></entity-table>
In your directive do this ..
angular.module('unioffice-centralApp')
.directive('entityTable', function () {
return {
restrict: 'E',
replace: true,
transclude : true,
templateUrl: '/components/directives/entity-table/entity-table.html',
scope: {
object: '=',
entity: '=',
attr: '=',
onDelete: '&', // function referencing
onEdit: '&' // function referencing
},
link: function (scope, element, attrs, controllers, transclude) {
scope.deleteFn = function (obj) {
scope.onDelete()(obj); // this invokes the deleteConfirm function in the controller
}
scope.editFn = function (obj) {
scope.onEdit()(obj); // this invokes the deleteConfirm function in the controller
}
}
};
});
In your controller ...
$scope.edit = function(projectType) {
$scope.projectType = projectType;
$scope.computerName = projectType.computerName;
$scope.isEdit = true;
};
// shows a delete modal window
$scope.deleteConfirm = function (projectType) {
Modal.confirm.deleteModal('Project type', projectType.computerName, function () {
Message.createMessage('project-type.message.delete.success', { projectType: projectType.computerName }, { type: 'warning', timeout: 4000 });
$scope.remove(projectType);
})();
};
PLUNKR
I have the following page
<body ng-controller="myController">
<table>
<tbody>
<tr ng-repeat="r in rows">
<div show-row></div>
</tr>
</tbody>
</table>
</body>
with the following Angular module
ng.module('myModule', [ ])
.controller('myController', ['$scope', function ($scope) {
$scope.rows = [a non-empty array of values]
}]).directive('showRow', function () {
return {
replace: true,
template: '<td>Hello!</td>'
};
});
My problem is that Hello! is shown once before the table and not, as I would expect, once for every row of the table.
I guess I have to use the scope property for the directive, but how?
The problem is with div which cannot be a children to tr. Change the div to td.
<body ng-controller="myController">
<table>
<tbody>
<tr ng-repeat="r in rows">
<td show-row></td>
</tr>
</tbody>
</table>
</body>
I'm having a similar problem with the following layout:
<table>
<table-header data="headers" order="order"></table-header>
<tbody>
<tr ng-repeat="...">
...
</tr>
</tbody>
</table>
The tableHeader directive looks like this:
.directive('tableHeader', [function () {
return {
restrict: 'E',
replace: true,
scope: {
data: '=',
order: '='
},
template: '\
<thead><tr> \
<th ng-repeat="header in ::data" \
ng-click="orderBy(header)"> \
{{:: header.name }} \
</th> \
</tr></thead>',
link: function (scope, elem, attrs) {
scope.orderBy = function (header) {
if (scope.order.by === header.prop) {
scope.order.reverse = !scope.order.reverse;
} else {
scope.order.by = header.prop;
}
};
}
};
Weird enough, the thead element ends up out of the table, instead of inside.
Edit: seems to be documented in https://github.com/angular/angular.js/issues/7295.
For some reason I am not able to access my isolate scope variable "index" in my link function. I have tried both # and = to see if it made any difference and this had no effect, I also tried using a word other than index (in case it was already in use by angular or something) with the same result. Error msg: ReferenceError: index is not defined.
directive:
var jobernizeDirectives = angular.module('jobernizeDirectives', []);
jobernizeDirectives.directive('viewLargeContent', function() {
return {
scope: {
index: '=index'
},
require: 'ngModel',
link: function (scope, el, attrs, ngModel) {
console.log(index);
function openEditor() {
console.log(index);
var main_container = angular.element('.main_container');
var view_frame = angular.element('.view-frame');
console.log(ngModel);
main_container.append('<div class="dimmer"></div>');
main_container.append(
'<div class="large-content' + index + '">'
+ '<textarea>' + ngModel.$viewValue + '</textarea>'
+ '<button>Submit Changes</button>'
+ '</div>'
);
var dimmer = angular.element('.dimmer');
var content_container = angular.element('.large-content' + index);
// content_container.css({ marginTop: (content_container.height()/-2), width: view_frame.width(), marginLeft: (view_frame.width()/-2) })
content_container.css({ height: (0.8*main_container.height()), width: view_frame.width(), marginLeft: (view_frame.width()/-2) })
content_container.find('button').on('click', function() {
var new_content = content_container.find('textarea').get(0).value;
ngModel.$setViewValue(new_content);
content_container.hide();
dimmer.hide();
});
}
// el.on('click', openEditor);
el.on('click', openEditor);
}
}
});
html:
<div data-ng-controller="resumesController">
<div class="row">
<div class="small-12 columns">
<h2>Your Resumes</h2>
</div>
</div>
<div class="row">
<div class="small-12 columns">
<table>
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Date Added</th>
<th>View/Edit Resume</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="resume in resumes">
<td>{{ resume.name }}</td>
<td>{{ resume.category }}</td>
<td>{{ resume.date_added }}</td>
<td><button index="le" view-large-content data-ng-model="resume.content">View Resume</button></td>
</tr>
</tbody>
<table>
</div>
</div>
</div>
Index is an attribute of you scope object, so you access it like this:
scope.index
Both '#' or '=' will work, the difference is that '#' will interpolate the value and update the isolated scope when it changes and '=' means Angular should keep the attribute and the isolated scope in sync.
If the variables have the same name you can use the syntactic sugar
scope: {
index: '#'
},
Here is a JSBin with your code.