VueJS Accordion Table - Appears outside of the table - javascript

I have a table where the data is fetched using ajax. I'm trying to have a table where each row has an associated hidden row and clicking on the row toggles the display of the hidden row. The hidden row contains an accordion.
The problem is that the accordion is getting all messed up and shows at the bottom of the table, rather than showing below the particular row that it was clicked on.
My code is as follows:
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th v-for="column in columns">
<span v-if="column == 'Predictive Price'">
{{column}}
<i class="fa fa-info-circle" v-tooltip="msg"></i>
</span>
<span v-else-if="column == 'Actual Price'">
{{column}}
<i class="fa fa-info-circle" v-tooltip="tooltip.actual_price"></i>
</span>
<span v-else>
{{column}}
</span>
</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="row in model" #click="showRow">
<td>
{{row.id}}
</td>
<td>
{{row.company_customer.customer_name}}
</td>
<td>
<i class="fa fa-map-marker"></i>
<small>
{{row.pickup_addr.address_1}}, {{row.pickup_addr.city}}, {{row.pickup_addr.postcode}}
</small>
</td>
<td>
<i class="fa fa-map-marker"></i>
<small>
{{row.pickup_addr.address_1}}, {{row.pickup_addr.city}}, {{row.pickup_addr.postcode}}
</small>
</td>
<td>
£{{row.predictive_price}}
</td>
<td>
£{{row.actual_price}}
</td>
<td>
n/a
</td>
<tr>
<td colspan="7" v-if="contentVisible">
<div class="accordian-body">
ACCORDION
</div>
</td>
</tr>
</tr>
</tbody>
</table>
<script>
export default {
methods: {
data() {
return {
msg: 'This is just an estimation!',
tooltip: {
actual_price: 'Click on the price to edit it.'
},
contentVisible: false,
}
},
rowRow() {
this.contentVisible = !this.contentVisible;
}
}
}
</script>
Where can I place the accordion div in order for it to display correctly?
EDIT:
Please see fiddle: https://jsfiddle.net/49gptnad/355/

It sounds like you want an accordion associated with every row, so really, you want two rows for each item of your data.
You can accomplish that by moving your v-for to a template tag that wraps both of your rows.
Additionally, you need to control whether content is visible on a row by row basis, so add a contentVisible property to each data item and use it to control whether your second row is visible or not.
console.clear()
var vm = new Vue({
el: '#vue-instance',
data: {
testing: [{
id: 1,
name: "Customer 1",
contentVisible: false
},
{
id: 2,
name: "Customer 1",
contentVisible: false
},
{
id: 3,
name: "Customer 3",
contentVisible: false
},
],
columns: ["id", "name"]
},
mounted() {
console.log(this.testing);
},
methods: {
showRow(data) {
this.contentVisible = !this.contentVisible;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<div id="vue-instance">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th v-for="column in columns">
{{column}}
</th>
</tr>
</thead>
<tbody>
<template v-for="row in testing">
<tr #click="row.contentVisible = !row.contentVisible">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
</tr>
<tr v-if="row.contentVisible">
<td :colspan="columns.length" >
<div class="accordian-body">
afasfafs
</div>
</td>
</tr>
</template>
</tbody>
</table>
</div>
Here is your updated fiddle.

Related

Binding and using an object's fields within an object returned by the server API with a PrimeNG data table

Good day
Currently I am returning an array of objects looking like:
{
attendeeCount: 5
bookDay: "2018-11-22T14:06:24.120Z"
bookingComment: "This is a test"
conferenceRoom: {id: 8, name: "Main Boardroom", seatingCount: 10, location: "Site Office", projector: "YES"}
employee: {id: 111, title: "Mr.", initials: "J", preferredName: "John", lastName: "Smith", …}
id: 1
refreshment: {id: 1, name: "Coffee, Tea and Water"}
timeSlot: "07:00 - 07:30"
}
The requirement then is that I should be able to render the PrimeNG data table using TypeScript like the below:
public getRoomRosterTable() {
this.conferenceRoomBookingService.getRoomRoster(this.dateValue, this.selectedConferenceRoom.id).subscribe(response => {
console.warn(response);
this.conferenceRoomBookings = response;
}, error1 => {
this.alertService.error(error1);
});
this.timeSlotCols = [
{field: 'timeSlot', header: 'Time Slot'},
{field: 'employee.preferredName' + 'employee.lastName', header: 'Slot Booked By'},
{field: 'attendeeCount', header: 'Attendee Count'},
{field: 'refreshment.name', header: 'Refreshment Details'},
{field: 'bookingComment', header: 'Booking Comment'}
];
}
Combined with html looking like:
<p-table [value]="conferenceRoomBookings" [reorderableColumns]="true" [columns]="timeSlotCols">
<ng-template pTemplate="header" let-columns>
<tr>
<th *ngFor="let col of columns">
<div style="text-align:center">
{{col.header}}
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-rowData let-columns="columns">
<tr>
<td *ngFor="let col of columns">
{{rowData[col.field]}}
</td>
</tr>
</ng-template>
</p-table>
This however only renders the columns that have direct data bound. I cannot seem to get the table to pick up properties of nested objects.
Is the above possible currently with PrimeNG, or do I need to create a custom DTO on the server returning only 'direct' fields for the PrimeNG table?
Could not get this to work with the PrimeNG table and resorted to using *ngFor combined with *ngIf wrapped in divs to detect nulls:
<table class="table-bordered">
<thead>
<tr>
<th>
<div style="align-content: center">
Time Slot
</div>
</th>
<th>
<div style="align-content: center">
Booked By
</div>
</th>
<th>
<div style="align-content: center">
Attendee Count
</div>
</th>
<th>
<div style="align-content: center">
Refreshment Requirement
</div>
</th>
<th>
<div style="align-content: center">
Booking Details
</div>
</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let conferenceRoomBooking of conferenceRoomBookings">
<td>
<div *ngIf="conferenceRoomBooking.timeSlot">
{{conferenceRoomBooking.timeSlot}}
</div>
</td>
<td>
<div *ngIf="conferenceRoomBooking.employee">
{{conferenceRoomBooking.employee.preferredName}} {{conferenceRoomBooking.employee.lastName}}
</div>
</td>
<td>
<div *ngIf="conferenceRoomBooking.attendeeCount">
{{conferenceRoomBooking.attendeeCount}}
</div>
</td>
<td>
<div *ngIf="conferenceRoomBooking.refreshment">
{{conferenceRoomBooking.refreshment.name}}
</div>
</td>
<td>
<div *ngIf="conferenceRoomBooking.bookingComment">
{{conferenceRoomBooking.bookingComment}}
</div>
</td>
</tr>
</tbody>
</table>

Angular JS: table with dynamic number of titles

I tried to create a table with a dynamic number of titles and sub titles. It should look like this:
Each title has 3 sub titles. But I can not know in advance how much headline I will have.
So in HTML it looks like:
<table class="table table-hover col-xs-12">
<thead>
<tr>
<th rowspan="2">Type ID</th>
<th colspan="3" ng-repeat="val in ctrl.vals">
<div class="val">
<span title="{{val}}">{{val}}</span> <!-- this is title -->
</div>
</th>
</tr>
<tr>
<th class="row-header" ng-repeat="val in ctrl.getNumberColumn() track by $index">{{ $index%3 == 0 ? "subtitle1" : $index%3 == 1 ? "subtitle2" : "subtitle3" }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="key in ctrl.keys">
<td class="row-key">{{key}}</td>
<td class="row-value" ng-repeat="val in ctrl.getNumberColumn() track by $index">
<div class="list-group" ng-init="data = ctrl.getDataByIndex($index, ctrl.items[key])">
<a class="list-group-item" ng-if="$index%3 == 0">{{data.avg_fps}} </a>
<a class="list-group-item" ng-if="$index%3 == 1">{{data.avg_cpu}} </a>
<a class="list-group-item" ng-if="$index%3 == 2">{{data.session}} </a>
</div>
</td>
</tr>
</tbody>
</table>
I understand that it looks confusing - so I would like to ask - is there an option for more simply constructing such a table?
angular.module('app', []).controller('ctrl', function($scope) {
$scope.titles = [{
title: 'One',
items: ['Sub1_1', 'Sub1_2']
}, {
title: 'Two',
items: ['Sub2_1']
},{
title: 'Three',
items: []
},
{
title: 'Four',
items: ['Sub4_1', 'Sub4_2', 'Sub4_3']
}];
})
table {
border-collapse: collapse;
}
table,
td,
th {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js">
</script>
<div ng-app='app' ng-controller='ctrl'>
<table>
<thead>
<tr>
<th rowspan="2">TypeId</th>
<th ng-repeat='item in titles' colspan='{{item.items.length}}' rowspan='{{item.items.length > 0 ? 1 : 2}}'>
{{item.title}}
</th>
</tr>
<tr>
<th ng-repeat-start='item in titles' ng-if='false'></th>
<th ng-repeat-end ng-repeat='sub in item.items'>{{sub}}</th>
</tr>
</thead>
</table>
</div>

DataTables with third party buttons

I have a page coded in Handlebars and I am fetching the data as json from nodejs. I am trying to render a button which is a third party button. When I don't use DataTables() then the buttons are correctly render and clicking them opens a third party login window for further processing.
However, when I enable DataTables, only the first page is correctly rendered and the buttons work, but it does not work for other pages when the number of elements exceed 10. I am not sure if this is an issue with DataTables or how the third party button is expected to behave, but I am suspecting that when I switch pages in DataTables, the parameters the button expects while rendering are not correctly sent. I am new to DataTables.
<body>
<div class="container">
<div class="jumbotron">
<h1>Last 100 NSE Annoucements</h1>
<h3>Top Annoucements by corporates listed on NSE</h3>
</div>
</div>
<div class="container">
<table class="table table-hover table-responsive table-sm" id="resultTable"">
<thead>
<tr>
<th class="col-sm-1" scope="row">Ticker</th>
<th class="col-sm-1" scope="row">Link</th>
<th class="col-sm-2" scope="row">Date</th>
<th class="col-sm-5" scope="row">Description</th>
<th class="col-sm-1" scope="row">Trade</th>
</tr>
</thead>
<tbody>
{{#each feedList}}
<tr>
<td> {{this.ticker}} </td>
<td> {{this.ticker}} </td>
<td> {{moment date=this.dateAdded format="DD-MM-YYYY h:mm:ss a"}} </td>
<td> {{this.purposeText}} </br> {{this.summaryText}} </td>
<td> <span> <kite-button href="#" data-kite="secret_key"
data-exchange="NSE"
data-tradingsymbol="{{this.ticker}}"
data-transaction_type="BUY"
data-quantity="1"
data-order_type="MARKET">Buy {{this.ticker}} stock</kite-button> </span></td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</body>
<script>
$(document).ready(function() {
$('#resultTable').DataTable({
"order": [[ 2, "desc" ]],
"columnDefs" : [{"targets":2, "type":"date"}]
});
});</script>
</html>
How to modify this - most probably custom rendering of the button as each row is displayed?
EDIT
I am trying to modify the DataTable by custom rendering the button each time - but its not working.
<body>
<div class="container">
<div class="jumbotron">
<h1>Last 100 NSE Annoucements</h1>
<h3>Top Annoucements by corporates listed on NSE</h3>
</div>
</div>
<div class="container">
<table class="table table-hover table-responsive table-sm" id="resultTable"">
<thead>
<tr>
<th class="col-sm-1" scope="row">Ticker</th>
<th class="col-sm-1" scope="row">Link</th>
<th class="col-sm-2" scope="row">Date</th>
<th class="col-sm-5" scope="row">Description</th>
<th class="col-sm-1" scope="row">Trade</th>
</tr>
</thead>
<tbody>
{{#each feedList}}
<tr>
<td> {{this.ticker}} </td>
<td> {{this.ticker}} </td>
<td> {{moment date=this.dateAdded format="DD-MM-YYYY h:mm:ss a"}} </td>
<td> {{this.purposeText}} </br> {{this.summaryText}} </td>
<td> {{this.ticker}} </td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</body>
<script>
$(document).ready(function() {
$('#resultTable').DataTable({
"order": [[ 2, "desc" ]],
"columnDefs" : [{"targets":2, "type":"date"},
{
targets: -1,
searchable: false,
orderable: false,
render: function(data, type, full, meta){
if(type === 'display'){
data = '<kite-button href="#" data-kite="scret" data-exchange="NSE" data-tradingsymbol=' + data + 'data-quantity="1" data-order_type="MARKET">Buy '+ data + 'stock</kite-button>';
}
return data;
}
]
});
});</script>
</html>

DataTables responsive issues

I'm trying to use DataTables.js on a few pages and I need to make them responsive. Multiple tables on a few different pages work great, but on one page the columns and width always end up sticking out of the container.
When I reduce the screen, the last column (action column) gets hidden, but when I reduce the screen further, it just stays that way and the table stretches out the container despite the width and maxwidth css properties.
<table id="mytable" class="table table-striped no-footer dt-responsive" data-order='[[ 4, "asc" ]]'>
<thead>
<tr role="row">
<th>One</th>
<th>Two</th>
<th>Threee</th>
<th>Four</th>
<th>Five</th>
<th data-orderable="false"> </th>
</tr>
</thead>
<tbody>
<tr>
<td>
<img class="img-thumbnail" src="(picture_url)" alt="" />
<span>Some Small text</span>
</td>
<td>
Value
</td>
<td>Value</td>
<td><i class="fa fa-circle"></i> Value</td>
<td data-sort="(sort value)"><span class="label label-info">Value</span></td>
<td>
<a href="(action_url)" title="Title" type="button"
class="btn btn-xs btn-success"><span><i class="fa fa-view"></i> Details</span></a>
</td>
</tr>
</tbody>
</table>
This is the initialisation js code:
var table = $('#mytable').DataTable({
"lengthMenu": [ 10, 25, 50, 75, 100 ],
"language": {
"emptyTable": "No information is available at this time."
}
});
I use this on a window resize (debounce):
table.responsive.recalc();
table.columns.adjust().draw();

vuejs v-if condition for input model

i m just learn vue.js
and i want to display a table data.my opinion is when display mode the table just show. and when i click edit button of the line of the table, i want this line convert to model.
this is my code:
```
<table class="table table-bordered">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>pass</th>
<th>action</th>
</tr>
</thead>
<tbody>
<template v-for="data in apidata" track-by="$index">
<tr>
<td>{{$index + 1}}</td>
<td>
<div v-show="data.editmode"><input v-model="data.name"></div>
<div v-else>{{data.name}}</div>
</td>
<td>
<div v-if=data.editmode><input v-model="data.name"></div>
<div v-else>{{data.name}}</div>
</div>
</td>
<td>
<button v-on:click="remove($index)" class="btn btn-danger">remove</button>
<button v-on:click="edit(data)" class="btn btn-danger">edit</button>
</td>
</tr>
</template>
</tbody>
</table>
```
my data is like this
[{name:'test', pass:'1'}, {name:'test2', pass:'2'}]
i bind a edit()function to listen the click event.
edit: function(data){
alert(data.editmode);
data.editmode = true;
}
i think when i click .becuase the data.editmode will change to true.
this line will convert to input mode . but its useless.
i have tried v-if=data.editmode , v-if="data.editmode" ,v-show="data.editmode" , still got nothing
i dnt know why?
You just need to include editmode in your data declaration so that it is a reactive data item.
new Vue({
el: 'body',
data: {
apidata: [{
name: 'test',
pass: '1',
editmode: false
}, {
name: 'test2',
pass: '2',
editmode: false
}]
},
methods: {
edit: function(data) {
data.editmode = !data.editmode;
}
}
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.27/vue.min.js"></script>
<table class="table table-bordered">
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>pass</th>
<th>action</th>
</tr>
</thead>
<tbody>
<tr v-for="data in apidata">
<td>{{$index + 1}}</td>
<td>
<div v-if="data.editmode">
<input v-model="data.name">
</div>
<div v-else>{{data.name}}</div>
</td>
<td>
<div v-if=data.editmode>
<input v-model="data.pass">
</div>
<div v-else>{{data.pass}}</div>
</td>
<td>
<button v-on:click="remove($index)" class="btn btn-danger">remove</button>
<button v-on:click="edit(data)" class="btn btn-danger">edit</button>
</td>
</tr>
</tbody>
</table>

Categories