Add new element between table rows by click on item - angularjs

I have a table with some items. I would like by click on item open a list of comments to this item.
I use directive for this aim and append data to my element. The issue is that data is appended to the right side of the table instead of put it between rows. I try to play with open\closing tr tag but it doesn't help either.
My html page:
<div id="content_people" ng-show="active=='people'" ng-controller="DevsListCtrl">
<table ng-table="tableParams" class="table">
<tr feedback-holder ng-repeat="d in $data">
<td add-new-team-member data-title='name' data-value="{{d.name}}" bs-tooltip="tooltip">{{d.name}}</td>
<td data-title='age'>{{d.age}}</td>
<td data-title='grade'>{{d.grade}}</td>
<td data-title='job'>{{d.job}}</td>
</tr>
</table>
</div>
My js directive:
mainApp.directive("feedbackHolder", ['$compile', 'teamSharedObj', function ($compile, teamSharedObj) {
return {
restrict: 'A',
link: function( scope, element, attrs ) {
element.bind('click', function() {
console.log("Click on feedback");
var el = angular.element('</tr><tr><div><input type="submit" value="Refresh"></div>');
$compile(el)(scope);
element.append(el);
});
}
}
}])
Could you advise me a right way to do this? Thanks.

If you want to insert your new content between rows, use element.after() instead of element.append
element.after(el);
Also the element you insert should look like this:
var el = angular.element('<tr><td colspan="4"><input type="submit" value="Refresh"></td></tr>');

You probably just need colspan like :
var el = angular.element('</tr><tr><td colspan="4"><input type="submit" value="Refresh"></td>');

Related

How to display a textbox in place of text in a column in a table on button-click in angularjs

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

Nesting a directive inside of a table

Is this possible? I want the ability to tidily swap out a table body depending on user input, so i just threw this little *test together to see if it would work, but it's loading all wonky, with the body preceding and exterior to the table itself in the DOM even though I nest it appropriately in my html. so my questions are thus:
1) what's this behavior all about? and
2) can i achieve what I want the way i'm going about it?
*simple fiddle
html:
<div ng-app="myApp" ng-controller="myController">
<table class="table">
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<my-directive></my-directive><!-- this should be the tbody -->
<tfoot>
<tr>
<td>Sum</td>
<td>$180</td>
</tr>
</tfoot>
</table>
</div>
js:
var app = angular.module("myApp", []);
app.directive("myDirective", function () {
return {
restrict: 'E',
template: '<tbody><tr><td>January</td><td>$100</td></tr><tr><td>February</td><td>$80</td></tr></tbody>',
};
});
You are currently rendering markup within a <my-directive></my-directive> element, which is messing up the table layout.
Instead, change your directive to an attribute-based directive and place it on the <tbody> element, replacing the content..
Template
</thead>
<tbody my-directive></tbody><!-- this should be the tbody -->
<tfoot>
Directive
return {
restrict: 'A',
template: '<tr><td>January</td><td>$100</td></tr><tr><td>February</td><td>$80</td></tr>'
};
See working fiddle.

AngularJS dynamic table with multiple headers based on hierarchical collections

I'm trying to create a table with two rows for header, based on a hierarchical collection. I've found that ng-repeat can't do that, and I'm trying to make the job with a directive and Angular.forEach.
Here the jsfiddle : http://jsfiddle.net/echterpat/RxR2M/9/
But my problem is that when I made the first display of table, collections were empty (they were filled by REST call afterward), so link method was not able to build all the table. And then when REST updated collections, link method was not called anymore...
Any idea to call directive after REST answer, and to fill my table with collected data ?
Directive with angular.forEach :
myApp.directive('myTable', ['$compile', function (compile) {
var linker = function (scope, element, attrs) {
var html = '<table BORDER="1"><thead>';
html += '<tr><th><button type="submit" class="btn btn-info">Back</button></th>';
angular.forEach(scope.myFirstCol, function (item, index) {
html += '<th colspan="{{item.mySecondCol.length}}" id="item_{{item.id}}"> {{item.name}}</th>';
});
html += '</tr><tr><th><input type="checkbox" ng-model="selectAll"/></th>';
angular.forEach(scope.myFirstCol, function (item2, index) {
angular.forEach(item2.mySecondCol, function (item3, index) {
html += '<th id="headerStep_{{item3.id}}">{{item3.name}}</th>';
});
});
html += '</tr></thead>';
html += '</table>';
element.replaceWith(html);
compile(element.contents())(scope);
};
return {
restrict: 'E',
rep1ace: true,
link: linker,
scope: {
myFirstCol: '=myFirstCol'
}
};
}]);
If you dont want to use a directive, you can go for nested tables:
<table BORDER="1">
<thead>
<tr>
<th>
<button type="submit" class="btn btn-info">Back</button>
</th>
<th ng-repeat="item in myFirstCol">{{item.name}}</th>
</tr>
<tr>
<th>
<input type="checkbox" ng-model="selectAll" />
</th>
<th ng-repeat="item in myFirstCol">
<table BORDER="1">
<tr>
<th ng-repeat="item2 in item.mySecondCol">
{{item2.name}}
</th>
</tr>
</table>
</th>
</tr>
</thead>
</table>

setting ng-href in <tr> elements

The following code makes the client.name an anchor on each client in clients. I am interested in having the entire <tr> element be that link however. ng-href does not work on the <tr> element.. what can I do so that the entire row is a single link instantiated by ng-href?
<tr ng-repeat="client in clients">
<td><a ng-href="#/user/{{client.tagid}}">{{client.firstname}}</a></td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
What I am looking to do is something like this.. which of course does not work..
<a ng-href="#/user/{{client.tagid}}">
<tr ng-repeat="client in clients">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
</a>
OR
<tr ng-repeat="client in clients" ng-href="#/user/{{client.tagid}}">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
You can use an ng-click (instead of onClick) as Jason suggests as well.
Something like:
HTML
<tr ng-repeat="client in clients" ng-click="showClient(client)">
<td><a ng-href="#/user/{{client.tagid}}">{{client.firstname}}</a></td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
Controller
$scope.showClient = function(client) {
$location.path('#/user/' + client.tagid);
};
And styling to make it show as an clickable element (wont work in IE7)
CSS
tr {
cursor: pointer;
}
// or
[ng-click] {
cursor: pointer;
}
I wrote a directive so that you can simply write:
<tr ng-repeat="client in clients" such-href="#/user/{{client.tagid}}">
The source:
app.directive('suchHref', ['$location', function ($location) {
return{
restrict: 'A',
link: function (scope, element, attr) {
element.attr('style', 'cursor:pointer');
element.on('click', function(){
$location.url(attr.suchHref)
scope.$apply();
});
}
}
}]);
I use my own Angular directive that automatically wraps every cell in the row with a link.
The advantages are:
You don't duplicate code.
There is a regular link in every cell so things like "Open in new tab" (middle button or CTRL+click) works as expected (in opposite of the ng-click version).
HTML usage:
<tr row-href="#/user/{{client.tagid}}">
<td>...</td>
<td>...</td>
</tr>
Directive code (in TypeSript):
export class RowHrefDirective implements ng.IDirective {
constructor(private $compile: ng.ICompileService) {
}
restrict = "A";
scope = {
rowHref: "#rowHref"
};
link = (scope: Scope, element: ng.IAugmentedJQuery, attrs: ng.IAttributes): void => {
const cells = element.children("td[skip-href!='yes'],th[skip-href!='yes']");
cells.addClass("cell-link");
for (const cell of cells.toArray()) {
const link = jQuery(`<a ng-href="{{ rowHref }}"></a>`);
this.$compile(link)(scope);
jQuery(cell).prepend(link);
}
}
}
Required CSS code (to fill the whole cell with the link):
td.cell-link,
th.cell-link {
position: relative;
}
td.cell-link a,
th.cell-link a {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
This is a CSS and HTML issue, not specific to AngularJS. The only allowed child of a <tr> is a <td>, and so you need to wrap the content of each cell in an anchor. You also need to make the anchor a block element to make it the full height/width of its container:
<tr ng-repeat="client in clients">
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.firstname}}
</a>
</td>
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.lastname}}
</a>
</td>
<td>
<a style="display: block;" ng-href="#/user/{{client.tagid}}">
{{client.inumber}}
</a>
</td>
</tr>
<tr ng-repeat="client in clients" ng-href="#/user/{{client.tagid}}">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
This is with the referrence to the options provided which may work.
I think this binds the entire row with the each field in the row. but is not clickable. how to do that. i mean we should be able to click so that another view/module can be open.
As requested by #sfs, here’s the solution which we’re using for ui-sref (Angular 1.5; TypeScript code, apologies for any inconvenience).
Credits: The code is based on the awesome answer by Martin Volek:
import { IDirective, IDirectiveFactory, ICompileService, forEach, element } from 'angular';
export default class RowUiSrefDirective implements IDirective {
restrict = 'A';
scope = { rowUiSref: '#rowUiSref' };
constructor(private $compile: ICompileService) { }
link = (scope, elm, attrs) => {
if (elm[0].tagName !== 'TR') {
throw new Error('This directive should only be used in <tr> elements.');
}
forEach(elm.children(), (cell) => {
if (cell.attributes['skip-href'] && cell.attributes['skip-href'].value !== 'false') {
return;
}
cell.className += ' cell-link';
let link = element('<a ui-sref="{{rowUiSref}}"></a>');
this.$compile(link)(scope);
element(cell).prepend(link);
});
};
static factory(): IDirectiveFactory {
let directive = ($compile: ICompileService) => new RowUiSrefDirective($compile);
directive.$inject = ['$compile'];
return directive;
};
}
Directive initialization:
import { module } from 'angular';
import RowUiSrefDirective from './rowUiSref';
module('app').directive('rowUiSref', RowUiSrefDirective.factory());
Example usage:
<table>
<tr ng-repeat="item in itemController.items"
row-ui-sref="state.item({itemId: '{{item.id}}'})">
<td>{{item.name}}</td>
<td>{{item.label}}</td>
</tr>
</table>
An ugly solution would be to just have 1 table cell which contains the link, then within that add another table with a table row and the other cells. So it would look like;
<tr ng-repeat="client in clients">
<a ng-href="#/user/{{client.tagid}}">
<table>
<tr>
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
</table>
</a>
</tr>
I do not agree with using tables for layout!
However, you are using JavaScript and angularjs, so you would be just as good adding a click event to the table row which sends the user to the url via window.location e.g.
<tr ng-repeat="client in clients" ng-click="ChangeLocation([yoururl])">
<td>{{client.firstname}}</td>
<td>{{client.lastname}}</td>
<td>{{client.inumber}}</td>
</tr>
Then have a function within your $scope to handle this;
$scope.ChangeLocation = function(url){
window.location = url;
}
Try for this...
HTML --->
<ul ng-repeat ="item in itemList ">
<li><a data-ng-href="{{getUrl(item)}}">{{item.Name}}</a></li>
</ul>
JS --->
$scope.getUrl = function (item) {
return '/<give your path here>/' + item.ID;
};
I adapted Martin Volek's Typescript code to make an AngularJS 1.x directive:
app.directive('rowHref', function ($compile)
{
return {
restrict: 'A',
link: function (scope, element, attr)
{
scope.rowHref=attr.rowHref;
var cells = element.children("td");
angular.forEach(cells, function (cell)
{
$(cell).addClass("cell-link");
var newElem = angular.element('<a ng-href="{{ rowHref }}"></a>');
$compile(newElem)(scope);
$(cell).append(newElem);
});
}
}
});
Add his same HTML and CSS

What is angular way to transform a table cell

The problem is as follows. I have a directive which builds some table, and i use ng-repeat to construct table rows dynamicly. Each row has two buttons for editing and deleting accordingly. I look for action with ng-click, but how then transform a cell with static text into a cell with an input field in angular way? I know how to do it with jquery. I look around with ng-switch, but i can't get it works inside ng-repeat on a table cell as expected. My code:
JS
order.directive('orderLines',function($http,calculateTotalQtyService,$compile){
return {
restrict: 'A',
link: function($scope,element, attrs){
$scope.editLine = function(line,order_id){
// alert ('Edit'+line.id);
some code here to perform transformation
}
$scope.deleteLine = function(idx){
var line_to_delete = $scope.order.lines[idx]
$http.post('/delete/line?id='+line_to_delete.id +'&order_id='+$scope.order.id).success(function(data){
$scope.order.lines.splice(idx,1);
$scope.order = data.ord;
$scope.order.customer = data.customer;
$scope.order.lines = data.lines;
var res = calculateTotalQtyService.set(data.lines);
$scope.total_kg = res[0];
$scope.total_piece = res[1];
});
}
},
templateUrl:'/assets/fragments/order/order_lines.html',
replace: true
}
});
and HTML
<div class="span12 fiche" id="lines">
<table class="table table-bordered" id="order_lines">
<thead class="header_lines">
<th>S.N.</th>
<th>Ref.</th>
<th>Label</th>
<th>Tva</th>
<th>Qty</th>
<th>Unite</th>
<th>Prix HT</th>
<th>Total HT</th>
<th></th>
</thead>
<tbody ng-switch="lines.length">
<tr id="no_record" ng-switch-when="0"><th colspan="9" style="text-align: center" >No records</th></tr>
<tr ng-repeat="line in order.lines">
<td>{{$index+1}}</td>
<td class='line-ref'>{{line.product_ref}}</td>
<td>{{line.label}}</td>
<td class='line-tva'>{{line.tva}}</td>
<td class='line-qty'>{{line.qty}}</td>
<td class='line-unity'>{{line.unity}}</td>
<td class='line-prix_ht'>{{line.prix_ht}}</td>
<td>{{line.prix_ht*line.qty}}</td>
<th class='control-buttons'>
<button class='btn editline' ng-click="editLine(line,order.id)"><i class='icon-edit'></i></button>
<button class='btn deleteline' ng-click="deleteLine($index)"><i class='icon-trash'></i> </button>
</th>
</tr>
</tbody>
</table>
</div>
So html is a template, that i use in directive. How perform transformation ? with ng-switch? but how, or there are other solutions ? I want to avoid jquery if it's possible. Any help would be appreciated.
So I got it with a custom directive, inspired by #laut3rry. For those who would be interested this is my solution:
Directive:
order.directive('editable', function(){
return {
restrict : 'E',
replace : true,
template: '<div><span ng-hide="editMode">{{line.qty}</span><input class="span1" ng-show="editMode" type="text" ng-model="line.qty"/></div>',
link : function(scope, element, attrs){
}
}
});
And in HTML, in my example it's for a qty cell only, that I need to change, but we can use it with any cell and with a little bit of modification, for example by passing cell value in the attribute of the directive and it can be universal:
<td class='line-qty'><editable></editable></td>
In my controller I initialize $scope.editMode = false the cell isn't editable by default and then in the ng-click="editLine()" handler we change $scope.editMode = true and the cell transforms in to the input field. So directives and directives and once more directives.... :)
For those who is interested, here the link to the plunk plunk

Resources