jQuery traverse upwards and find - javascript

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.

Related

Multiple table rows as single component

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

After adding new <tr> to table the searching/sorting functionality has broke

I am using a bootstrap admin preset theme and having trouble with their table functionality. Previously the table would display a searching function in the top right and allow you to sort the table by rows. I added a new table row for each entry in to the table and it broke this functionality. It has nothing to do with the 'hide' or 'show' on the second row but simply the addition of the second row for each entry. I had a brief browse around and think it has something to do with the number of elements in each row of the table that the search is trying to run on and there being a mismatch.
Is there any way I can still implement searching/sorting even after adding a second row to my table?
The code is as follows:
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th>Session Name</th>
<th>Provider</th>
<th>Status</th>
<th>Pricing Type</th>
<th>Subscription Type</th>
<th>JIRA Number</th>
<th>Accept Port</th>
<th>IP Addresses</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Session Name</th>
<th>Provider</th>
<th>Status</th>
<th>Pricing Type</th>
<th>Subscription Type</th>
<th>JIRA Number</th>
<th>Accept Port</th>
<th>IP Addresses</th>
</tr>
</tfoot>
<tbody>
{% for item in session_details %}
<tr onclick = "rowClick(this)">
<td>{{ item.session_name }}</td>
<td>{{ item.client_name }}</td>
<td>{{ item.current_status }}</td>
<td>{{ item.pricing_type }}</td>
<td>{{ item.subscription_type }}</td>
<td>{{ item.jira }}</td>
<td>{{ item.accept }}</td>
<td>
{% for ips in item.IP_Addresses %}
<li>{{ ips.ip_addr }}</li>
{% endfor %}
</td>
</tr>
<tr bgcolor="#f8f9fa">
<td colspan="8">
{% for notes in item.Notes %}
<p><b>Note: </b>"{{ notes.note }}"</p><p><small><strong> Time of entry: </strong><i>{{notes.time_now}}</i></small></p>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
function rowClick(x)
{
var content = $(x).text().split('\n')[1];
console.log(content);
}
</script>
<script>
$( document ).ready(function()
{
console.log("ready!");
$("td[colspan=8]").find("p").hide();
$("table").click(function(event) {
event.stopPropagation();
var $target = $(event.target);
if ( $target.closest("td").attr("colspan") > 1 )
{
$target.slideUp();
} else
{
$target.closest("tr").next().find("p").slideToggle();
}
});
});
</script>
</div>
The error message that is produced in the developer console:
Uncaught TypeError: Cannot set property '_DT_CellIndex' of undefined
$.click() is a function that can't be used with new elements. It is initialized when the document is ready.
To use a function click with dynamic elements, use the function $.on('click', () => {}) http://api.jquery.com/on/

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>

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