Multiple table rows as single component - javascript

What would be a way to have multiple table rows in a single Angular component ?
I would like to display two rows per item of a given list, and have it in an HTML table.
I tried using ng-template with a component as attribute to avoid having a component tag breaking the table flow, but the input won't work in that case. Ideally I'm looking for a way to remove the component tag from the dom...
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container app-located-person
*ngFor="let person of persons"
[person]="person">
</ng-container>
</tbody>
</table>
App located person
<tr>
<td>{{ person.name }}</td>
<td>{{ person.city }}</td>
</tr>
<tr *ngIf="details">
<td>Last connection</td>
<td>{{ person.lastConnection }}</td>
</tr>

I finally made it not to break the table dom flow by using display: table-row-group; on the component node :)

Why don't you include the tr's inside the ng-container tag?
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container
*ngFor="let person of persons"
[person]="person">
<tr>
<td>{{ person.name }}</td>
<td>{{ person.city }}</td>
</tr>
<tr *ngIf="details">
<td>Last connection</td>
<td>{{ person.lastConnection }}</td>
</tr>
</ng-container>
</tbody>
</table>
If you want to use a component:
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container
*ngFor="let person of persons">
<app-located-person [person]="person"></app-located-person>
</ng-container>
</tbody>
</table>

Try the following:
<table>
<thead>
<th>Name</th><th>City</th>
</thead>
<tbody>
<ng-container *ngFor="let person of persons">
<tr>
<td>{{person.name}}</td>
<td>{{person.city}}</td>
</tr>
<tr *ngIf="person.lastConnection">
<td>Last connection</td>
<td>{{person.lastConnection}}</td>
</tr>
</ng-container>
</tbody>
</table>
Stackblitz: Link

Related

Appending from one table to another then deleting/manipulating data

I am trying to add from one table to another with .click and i got it to work
but now when i try to use the search field on the top table it clears the appended rows from the bottom table
I need to get these to start generating a table under it so that i can delete them all together
$(document).ready(function(){
$("#student-table2 tbody tr").click(function(){
$(this).css("background-color", "#f4a941")
.appendTo("#student-table3 tbody");
});
$("#student-table2").DataTable();
$("body").on("click", "#student-table2 tbody tr", function(){
$("#student-table3").data("stu-id", $(this).data("id"))
.data("stu-name", $(this)
.data("name"));
});
$("#access-table").DataTable();
$(".datetimepicker").datetimepicker({
format: 'MM/dd/yyyy hh:mm:ss',
});
});
Like i mentioned, it seems i can add the data to the table , but it wont store the row i select on table 2 when i use the search field atop the first table
I was thinking , maybe i can just have jquery generate the entire table with table placeholders already set in place? and not have it at all in HTML like i do, see under, i have student-table and student-table2 stacked
Here's my HTML
{% include "core/header.html" %}
{% load widget_tweaks %}
<section class="ids-section form-section">
<h2>{{ title }}</h2>
<h2> All Students </h2>
<table id="student-table2" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>License Plate</th>
<th>Active</th>
<th>Code</th>
<th>Added</th>
</tr>
</thead>
<tbody>
{% for stu in students %}
<tr data-id="{{ stu.id }}" data-name="{{ stu.name }}">
<td>{{ stu.name }}</td>
<td>{{ stu.school }}</td>
<td>{{ stu.license_plate }}</td>
<td>{{ stu.active }}</td>
<td>{{ stu.code }}</td>
<td>{{ stu.created }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2> Selected for Delete </h2>
<table id="students-table3" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>License Plate</th>
<th>Active</th>
<th>Code</th>
<th>Added</th>
</tr>
</thead>
<tbody>
<br>
<tr data-id="{{ stu.id }}" data-name="{{ stu.name }}">
<td>{{ stu.name }}</td>
<td>{{ stu.dealership }}</td>
<td>{{ stu.license_plate }}</td>
<td>{{ stu.active }}</td>
<td>{{ stu.code }}</td>
<td>{{ stu.created }}</td>
</tr>
</tbody>
</table>
</section>
</div>
{% include "core/footer.html" %}
I figured out that i actually was on the right track, i didnt know .dataTables() was a bootstrap marker for the tables so i simplified the remfunc.js file to
/* Main part- on click adds to second table */
$(document).ready(function(){
$("#student-table2 tbody tr").click(function(){
$(this).appendTo("#student-table3 tbody");
});
/* Formats the table to coginate,
gives it an inputFilter and wraps it.
*/
$("#student-table2").DataTable();
});
$("#access-table").DataTable();
$(".datetimepicker").datetimepicker({
format: 'MM/dd/yyyy hh:mm:ss',
});
});
with and html file that looked like
{% include "core/header.html" %}
{% load widget_tweaks %}
<section class="ids-section form-section">
<h2>{{ title }}</h2>
<h2> All Students </h2>
<table id="student-table2" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>License Plate</th>
<th>Active</th>
<th>Code</th>
<th>Added</th>
</tr>
</thead>
<tbody>
{% for stu in students %}
<tr data-id="{{ stu.id }}" data-name="{{ stu.name }}">
<td>{{ stu.name }}</td>
<td>{{ stu.school }}</td>
<td>{{ stu.license_plate }}</td>
<td>{{ stu.active }}</td>
<td>{{ stu.code }}</td>
<td>{{ stu.created }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2> Selected for Delete </h2>
<table id="students-table3" class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>School</th>
<th>License Plate</th>
<th>Active</th>
<th>Code</th>
<th>Added</th>
</tr>
</thead>
<tbody>
<br>
<tr data-id="{{ stu.id }}" data-name="{{ stu.name }}">
<td>{{ stu.name }}</td>
<td>{{ stu.dealership }}</td>
<td>{{ stu.license_plate }}</td>
<td>{{ stu.active }}</td>
<td>{{ stu.code }}</td>
<td>{{ stu.created }}</td>
</tr>
</tbody>
</table>
</section>
</div>
{% include "core/footer.html" %}

Vue.Draggable for tables with more than one tbody

I have table with difficult structure. The real structure of my table is much more difficult.
I try to show it by a simple example.
<table>
<thead>
<th>id</th>
<th>name</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr colspan="2">
<td>1</td>
</tr>
</tbody>
<tbody>
<tr>
<td>1</td>
<td>1</td>
</tr>
<tr colspan="2">
<td>1</td>
</tr>
</tbody>
</table>
I use vuejs, and I need to have sortable table (I use vuedraggable component https://github.com/SortableJS/Vue.Draggable).
I have item component with template like this.
<template>
<tbody class="item">
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
</tr>
<tr colspan="2">
<td>{{ item.description }}</td>
</tr>
</tbody>
</template>
And I use it with draggable.
<draggable v-model="items" :element="'table'" :options="{draggable: '.item'}">
<item-component v-for="(item, index) in items" :item="item" :key="item.id">
</item-component>
</draggable>
The Draggable component create outer 'table' element. Everything is working, but how can I add 'thead'?
I try to create one more component - items:
<template>
<table>
<thead>
<th>1</th>
<th>2</th>
</thead>
<slot></slot>
</table>
</template>
But this is not working:
<draggable v-model="items" :element="items-component" :options="{draggable: '.item'}">
<item-component v-for="(item, index) in items" :item="item" :key="item.id">
</item-component>
</draggable>
Since VueDraggable is a custom component, when using the DOM as your template eg. table you will be subject to some restrictions that are inherent to how HTML works, because Vue can only retrieve the template content after the browser has parsed and normalized it.
This will lead to issues when using custom components with elements that have such restrictions
A workaround is to use the is special attribute:
https://v2.vuejs.org/v2/guide/components.html#DOM-Template-Parsing-Caveats
<table>
<thead>
<th>1</th>
<th>2</th>
</thead>
<div is="draggable" element="div" v-model="items">
<tbody v-for="i in items">
<tr>
<td>{{i.id}}</td>
<td>{{i.name}}</td>
</tr>
<tr colspan="2">
<td>{{ item.description }}</td>
</tr>
</tbody>
</div>
</table>

Angular2 Clickable table row, except last cell

I have a table with data, and my last cell is a delete button to be able to delete a row.
The problem I'm facing is that my rows are clickable which take me to another page to edit the element, and so when I click the delete button, it deletes the element but also takes me to the edit page.
Here is my code :
<table class="data-table-format">
<thead>
<tr>
<th>id</th>
<th>Maker</th>
<th>Model</th>
<th>Year</th>
<th></th>
</tr>
</thead>
<tbody>
<tr *ngFor="let car of pagedItems" (click)="editCar(car)">
<th>{{ car.car_id }}</th>
<td>{{ car.car_maker }}</td>
<td>{{ car.car_model }}</td>
<td>{{ car.car_year }}</td>
<td><i class="material-icons" style="color:red" (click)="deleteCar(car.car_id)">delete_forever</i></td>
</tr>
</tbody>
</table>
Any suggestion on how to do it with angular/typescript ?
You can try this. This is not jQuery
<tbody>
<tr *ngFor="let car of pagedItems" (click)="editCar(car)">
<th>{{ car.car_id }}</th>
<td>{{ car.car_maker }}</td>
<td>{{ car.car_model }}</td>
<td>{{ car.car_year }}</td>
<td><i class="material-icons" style="color:red" (click)="$event.stopPropagation();deleteCar(car.car_id)">delete_forever</i></td>
</tr>
</tbody>

jQuery traverse upwards and find

I have a table which uses jQuery sortable to drag-drop and sort elements in a table.
When dropping an element into a "sortable-row" , I want to read the data-id from the previous "section-row" .
I've managed to achieve this for when the row is dropped in the row directly beneath a "section-row", or 2 levels below.
First level down :
($(ui.item[0]).closest('tr').prev('.stop-row').data('id');
Second level down :
$(ui.item[0].previousElementSibling).closest('tr').prev('tr.stop-row').data('id');
The problem is that a "section" can have any amount of rows added to it, so I need some kind of loop which will check if the previous element is a "section-row", if not, check on the following previous.
How do i achieve this with jQuery?
My Table:
<table class="table table-bordered table-responsive">
<thead>
<tr>
<td>Assignment</td>
</tr>
<tr>
<td>Type</td>
</tr>
<tr>
<td>Time</td>
</tr>
<tr>
<td>Level</td>
</tr>
</thead>
<tbody class="sortable">
<tr class="section-row" data-id="{{ id }}">
<td> Section-{{ id }}</td>
</tr>
<tr class="sortable_row">
<td>{{ assignment }}</td>
<td>{{ type }}</td>
<td>{{ time }}</td>
<td>{{ level }}</td>
</tr>
</tbody>
</table>
You can do this:
$(ui.item[0]).closest('tr').prevAll('.section-row:first').data('id');
It will go to the closest tr, search all preceeding tr and stop at the first one with the class .section-row.

angular table with dynamic column names

Is it possible to populate a table with angular.js without defining the column names prior to the 'ng-repeat'? For example this is how I'm currently populating the table..
<table class="table">
<thead>
<tr>
<th>Arup Mnemonic</th>
<th>Organism</th>
<th>Test</th>
<th>Result</th>
<th>Source</th>
<th>Source Value</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in data">
<td>{{ x.Arup_Mnemonic }}</td>
<td>{{ x.organism }}</td>
<td>{{ x.test }}</td>
<td>{{ x.result }}</td>
<td>{{ x.source }}</td>
<td>{{ x.source_value }}</td>
</tr>
</tbody>
</table>
Is it possible to remove all the hard coding and have the scope variable determine the column names along with and data ?
Quick Edit:
heres a quick look at the data in its current state.. I need the key in the key:value elements of this object. Is there a way to get those values with pure javascript ?
My understanding is that you don't know what the columns are beforehand. So, you need the keys of the first object to understand what the columns are.
angular:
var obj = data[0];
$scope.columns = Object.keys(obj).filter(function(key) {
if (obj.hasOwnProperty(key) && typeof key == 'string') {
return key;
}
});
$scope.format = function(str) {
return str.replace('_',' '); //do the rest of the formatting here.
}
html:
<table class="table">
<thead>
<tr>
<td ng-repeat="column in columns">
{{format(column)}}
</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="datum in data">
<td ng-repeat="column in columns">
{{datum[column]}}
</td>
</tr>
</tbody>
</table>
Edit: Took the filter on the keys from another answer as good practice when getting keys from objects.
Why not use a own model for your headlines to iterate through it?
Let headlines be an array, holding up all possible headlines, one for each index.
<table class="table">
<thead>
<tr ng-repeat="headline in headlines">
<th>{{ headline }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in data">
<td>{{ x.Arup_Mnemonic }}</td>
<td>{{ x.organism }}</td>
<td>{{ x.test }}</td>
<td>{{ x.result }}</td>
<td>{{ x.source }}</td>
<td>{{ x.source_value }}</td>
</tr>
</tbody>
</table>
A possible solution (please note that this is not tested):
// in controller
$scope.headlines = Object.keys(data[0]).filter(function(key) {
if (data[0].hasOwnProperty(key) && typeof key == 'string') {
return key;
}
});
<tr data-ng-repeat="(key,val) in gridData">
<th></th>
<th data-ng-repeat="col in columns" data-ng-init="CurrKey = col.key">{{val[CurrKey]}}
</th>
</tr>

Categories

Resources