Why won't "draggable = 'true'" work on React rendered component? - html

this is driving me mad and hope someone might be able to help.
I have this React.Component:
var Vehicle = React.createClass({
ondragend: function(e) {
e.preventDefault();
// Logic here
console.log('onDragOver');
},
ondragstart: function(e){
e.preventDefault();
console.log('ondragstart');
},
render: function() {
that = this
var loads = this.props.truck.map(function(load , i){
load.truckid = i
return (
<tr key={i} draggable="true" dragstart={that.ondragstart} dragend={that.ondragend}>
<td>
{load.load_number}
</td>
<td>
{load.stops[0].location_name}
</td>
<td>
{load.stops[1].location_name}
</td>
</tr>
)
})
return (
<div className="panel panel-primary" draggable="true">
<VehiclePanelHeading vehicleNbr={this.props.vehicleNbr}></VehiclePanelHeading>
<div className="panel-body" >
<table className="table">
<tbody>
{loads}
</tbody>
</table>
</div>
</div>
)
}
});
As you can see, I am trying to make the s draggable. Unfortunetly, this won't work, even if I use the Chrome dev tools to manually add this into the html in the browser.
I have tried removing my link to Bootstrap incase this is something to do with the CSS rules, and also tried to render just a html table with no dynamic values.
I can't see how the code in this fiddle:
jsFiddle
Works by setting the draggable=true in the render function, but mine won't.
Thanks in advance for any help.
Edit
Added the dropEnd/Start handlers but no change.
Curiously, if I add draggable=true to the div.panel container, this is draggable whilst the containing s remain not.
Update
If I create a quick .html page with this table:
<table className="table">
<thead>
<tr>
<td>Name</td>
<td>Tangyness</td>
</tr>
</thead>
<tbody>
<tr draggable="true">
<td>Apple</td>
<td>4</td>
</tr>
<tr draggable="true">
<td>Orange</td>
<td>7</td>
</tr>
</tbody>
</table>
Then the desired draggble = true works on the table rows. However, if I paste this into the React render function:
return (
<div className="panel panel-primary" >
<VehiclePanelHeading vehicleNbr={this.props.vehicleNbr}></VehiclePanelHeading>
<div className="panel-body" >
<table className="table">
<thead>
<tr>
<td>Name</td>
<td>Tangyness</td>
</tr>
</thead>
<tbody>
<tr draggable="true">
<td>Apple</td>
<td>4</td>
</tr>
<tr draggable="true">
<td>Orange</td>
<td>7</td>
</tr>
</tbody>
</table>
</div>
</div>
)
Then suddenly, the 'draggability' is lost.

It should work, but you probably want to implement onDragOver event(s) too. Otherwise it will look like it doesn't work because you can drag your component, but don't have any legal place to drop it. onDragOver lets you specify if an element accepts dropping and which elements it accepts.
As you can see in the fiddle you linked there are onDragOver events which look something like this
onDragOver: function(e) {
e.preventDefault();
// Logic here
}
Calling e.preventDefault(); tells the browser that dropping is possible here. You can put the onDragOver event on any of your parent elements, or on the tr itself. You can read more about drop targets here. If you remove the onDragOver event from the jsFiddle you linked the code in the fiddle stops functioning too.
If you implement onDragOver you will be able to implement an onDrop event on your table that handles dropped tr elements.
Here is your code with the events implemented:
var Vehicle = React.createClass({
onDragOver: function(e) {
e.preventDefault();
// Logic here
console.log('onDragOver');
},
onDragStart: function(e){
e.dataTransfer.setData('id', 'setTheId');
console.log('onDragStart');
},
onDrop: function(e) {
console.log('onDrop');
var id = event.dataTransfer.getData('id');
console.log('Dropped with id:', id);
},
render: function() {
that = this;
var loads = this.props.truck.map(function(load , i){
load.truckid = i
return (
<tr key={i} draggable="true" onDragOver={that.onDragOver} onDragStart={that.onDragStart}>
<td>
{load.load_number}
</td>
<td>
{load.stops[0].location_name}
</td>
<td>
{load.stops[1].location_name}
</td>
</tr>
)
})
return (
<div>
<div className="panel-body" >
<table className="table" onDrop={this.onDrop}>
<tbody>
{loads}
</tbody>
</table>
</div>
</div>
)
}
});
Here is a jsFiddle of this: http://jsfiddle.net/kb3gN/10761/

The reason that the item doesn't seem to drag is you have e.preventDefault(); inside onDragStart function, which prevents it from showing the default dragging movement. Just remove that line, so it would look like this and it should work:
var Vehicle = React.createClass({
...
onDragStart: function(e){
// REMOVED THIS LINE
//e.preventDefault();
console.log('ondragstart');
},
...

Related

Datatables: delete row on the client side

I have a SpringBoot application that uses datatables ,
here my datatable on the template
<table id="example" class="display" style="width:100%">
<thead>
<tr>
<th>Position</th>
<th>Actions1</th>
<th>Actions2</th>
</tr>
</thead>
<tbody>
<tbody>
<tr th:each="pic: ${pics}" >
<td class="col_name" >
<div class="box small">
<img th:src="${pic}"/>
</div>
</td>
<td class="col_actions">
<a style="color:#808080; margin-right: 10px;">
<input type="radio" name="${pic}" th:field="*{nadal}" th:value="${pic}" >Nadal<br>
</a>
</td>
<td><button>Delete</button></td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Position</th>
<th>Actions1</th>
<th>Actions2</th>
</tr>
</tfoot>
</table>
and the javascript code on the same page:
<script type="text/javascript">
$(document).ready(function() {
$('#example').DataTable({
searching: false,
paging: false
}).on("click", "button", function(){
alert('deleting row');
console.log($(this).parent());
table.row($(this).parents('tr')).remove().draw(false);
});
});
</script>
but When I click it makes a server submit of the form
try this:
<script type="text/javascript">
$(document).ready(function() {
const table = $('#example').DataTable({
searching: false,
paging: false
}).on("click", "button", function () {
alert('deleting row');
console.log($(this).parent());
table.row($(this).parents('tr')).remove().draw(false);
});
});
</script>
The easiest way to do whatever you want regardless of the scenario in all programming languages is just create a variable and an if statement. create a Boolean variable in the start and set the value to false. Whenever you want to display something or not display it, just create an if statement saying
if(<name of variable>){
display()
}else{
dontDisplay()
}
You don't have to say === true, you just need to give the variable's name since if you give the name it defaults to true, you only need to say === false for an else if statement.
This works all the time and you can also eliminate false positives, negatives or double alerts in many cases.

ng-repeat highlight all rows but also deselect, select

I have a basic html table where i need to have all the rows initially highlighted when the table is created. Also, if the user clicks the row it un highlights and clicked again highlights.
I have the click on a row, and it highlights. If you click again it un highlights.
I just need to initially highlight all rows possibly by ng-repeat. It also needs to release the highlighting when the row is clicked again and then highlight back. userData is just a line of text for each row
HTML
<table class="superusertable" cellpadding="5" cellspacing="0">
<tbody class="table-font">
<tr ng-init="" ng-repeat="source in userData"
ng-model="source.fromSourceID"
ng-class="{'sourcesSelected': source.sourcesSelected}"
ng-click="select(source)">
<td width="290px">
<div class="action-checkbox"; width="290px">{{source.fromSourceID}}
</div>
</td>
</tr>
</tbody>
</table>
angular
$scope.select = function(item) {
item.sourcesSelected ? item.sourcesSelected = false : item.sourcesSelected = true;
};
You can just add a function to the ng-init attribute on your tr. Just pass in your item and set it to true. Then like Aluan said in a comment, you can just make your ng-click function simpler by doing item.sourcesSelected = !item.sourcesSelected.
html
<table class="superusertable" cellpadding="5" cellspacing="0">
<tbody class="table-font">
<tr ng-init="init(source)"
ng-repeat="source in userData"
ng-model="source.fromSourceID"
ng-class="{'sourcesSelected': source.sourcesSelected}"
ng-click="select(source)">
<td width="290px">
<div class="action-checkbox"; width="290px">{{source.fromSourceID}}</div>
</td>
</tr>
</tbody>
</table>
angular
$scope.select = function(item) {
item.sourcesSelected = !item.sourcesSelected;
};
$scope.init = function(item) {
item.sourcesSelected = true;
}
On a side note, you can completely eliminate the ng-init and init function by setting item.sourcesSelected = true when you are retrieving your data.
There are too many errors i can observe.
ng-init="" not required
ternary operator is wrong you should do something following:
item.sourcesSelected = item.sourcesSelected ? false : true;

ng-repeat not compiling directive inside table row

I have this table that when you click on the table row this gets "expanded"(it actually slide another table row with the table's colspan), for this I built this angular directive
app.directive('dirt', function($compile){
return{
restrict:'A',
scope:{
},
replace: true,
compile:function(element, attrs){
element.next().children().children().hide();
element.next().children().hide();
var table = element.parent().parent();
var colspan = table.find('tr:first > th').length;
console.log(table.find('tr'))
if(!attrs['compiled']){
var tr = element.next();
tr.children().attr('colspan', colspan);
$compile(tr.children());
}
element.bind('click', function(){
event.stopPropagation();
element.next().children().slideToggle();
element.next().children().children().slideToggle();
});
}
}
});
it's called dirt, and you put it in the tr which you need to click to expand the next tr
something like this
<tbody>
<tr dirt>
<td>123465</td>
<td>A123</td>
<td>7455</td>
<td>MX</td>
<td>US</td>
<td>2</td>
<td>75000</td>
<td>7500</td>
<td>784</td>
</tr>
<tr>
<td>
<div style="width:100%;min-height:1px;background-color:yellow;float:left;">
<div class="col-xs-6">
<span style="font-size:60px;">A4</span>
</div>
<div class="col-xs-6">
<span>rklgjnrkelgtjnkelrtm;lremt;lermt;lremt;lermt</span>
<br />
rlgtjknrekltrmnekltmret;reltmklertmnkelrt
<br />
klgmkldgmnjklfdngmkldfng,mdfgn,dfmgndf,g
</div>
</div>
</td>
</tr>
</tbody>
I have this The way is needed to show how this works with only one set of tr, you just need to click on the first table row to expand it
The problem here is that when I try to use ng-repeat-start and end this happens
plunkr failed
I don't know how to compiled the second row affected by the dirt directive so it can be recognized for the ng-repeat dir, hope you know something about
thanks.

Bootstrap datetimepicker issue instide a table-responsive class

I am using this (https://github.com/Eonasdan/bootstrap-datetimepicker) Date and time picker for my website, and when you open the datetime picker in a table-responsive class it does not show the date picker on top the table unless in the css you add .table-responsive { overflow:visible !important } in the css. Its all well and good doing this, but then when you shrink the screen or use it on a mobile / tablet, the table is no longer responsive and hangs off the side of the screen.
Please see this (https://jsfiddle.net/daza110/6abxn644/3/) fiddle which shows it opening correctly until you shrink the screen.
And please see this (https://jsfiddle.net/daza110/6abxn644/4/) fiddle which shrinks the table correctly, but does not show the calendar properly.
<div class="panel-body">
<div class="table-responsive">
<table class="table table-condensed table-hover table-striped text-center bgwhite" id="accountTable">
<thead>
<tr>
<th class="col-sm-2">Debt Ref</th>
<th class="col-sm-2">Due Date</th>
<th class="col-sm-2">Amount Paid</th>
<th class="col-sm-2">Account</th>
<th class="col-sm-2">Reconcile Date</th>
</tr>
</thead>
<tbody>
<tr class="armitage">
<td>
<div>NOR087-DAN052</div>
</td>
<td>
<div>05/01/2016</div>
</td>
<td>
<div>180.00</div>
</td>
<td>
<div class="col-sm-12">Paralegal (951)</div>
</td>
<td>
<div class="col-sm-12">
<input type="text" placeholder="Reconcile Date" name="dates[ifbZ6A4b6r568bad40cd473]" id="dates-ifbZ6A4b6r568bad40cd473" class="form-control ">
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
Jquery
jQuery('#dates-ifbZ6A4b6r568bad40cd473').datetimepicker({
format: "DD/MM/YYYY"
});
UPDATE
I hacked this but it isnt nice, I added a PHP function that attaches a DatePicker and then did the following jquery code, this removes the table-responsive and adds a temp class on show then on hide removes temp class and adds the table-responsive again:
function attachDatePick($fieldId)
{
?>
<script type="text/javascript">
jQuery(function()
{
jQuery('#<?echo $fieldId;?>').datetimepicker().on('dp.show',function()
{
jQuery(this).closest('.table-responsive').removeClass('table-responsive').addClass('temp');
}).on('dp.hide',function()
{
jQuery(this).closest('.temp').addClass('table-responsive').removeClass('temp')
});
});
</script>
<?
}
I don't understand too much what you need but is maybe this?
.table-responsive {
overflow-x: inherit;
}
See in this fiddle
easy way is setting position: static for datepicker wrapper. For instance
<td>
<div class="col-sm-12">
<input type="text" placeholder="Reconcile Date" name="dates[ifbZ6A4b6r568bad40cd473]" id="dates-ifbZ6A4b6r568bad40cd473" class="form-control ">
</div>
</td>
you can set .col-sm-12 {position: static}
I haven't found any answer about this question that really pleases.
So I adapted a another code for bootstrap dropdown with same problem inside .table-responsive
below is the main code, that I put on window:
window.setDatapickerEvents = ($parentElement) => {
$($parentElement).on('dp.show', function (e) {
const $e = $(e.target);
const $input = $e.find('input').first();
const $btn = $e.find('span.input-group-addon').first();
const $dropdownMenu = $e.find('.dropdown-menu');
const eOffset = $e.offset();
const btnWidth = $btn.outerWidth();
const inputWidth = $input.outerWidth();
const dropdownWidth = $dropdownMenu.outerWidth();
const dropdownHeight = $dropdownMenu.outerHeight();
$('body').append($dropdownMenu.detach());
$dropdownMenu.css({
'top': eOffset.top - dropdownHeight,
'left': eOffset.left + inputWidth + (btnWidth / 2) - dropdownWidth + 20,
'width': dropdownWidth,
'height': dropdownHeight,
});
});
$($parentElement).on('dp.hide', function (e) {
const $e = $(e.target);
const $dropdownMenu = $e.find('.dropdown-menu');
$e.append($dropdownMenu.detach());
$dropdownMenu.hide();
});
}
And to enable it inside scripts tag in your page
setDatapickerEvents('.table-responsive');
Before - Problem
After - Resolved
I hope it helps anyone

Get the width of parent <td> from angularjs directive template

Im trying to figure out if its possible to get the width of the parent my directive is going to be placed in.
Keeping it simple I have some directive my-directive which Im placing inside of a table:
<table>
<tr>
<td><my-directive ..../></td>
<td><my-directive ..../></td>
<td><my-directive ..../></td>
<td><my-directive ..../></td>
</tr>
</table>
And inside my-directive Iwant to know the width of my parent <td> so I could display my content properly - with more or less data according to the width
Can it be done?
Update:
My HTML code:
<table class="table">
<thead>
<tr>
<td width="5%"></td>
<td width="5%"></td>
<td width="85%"></td>
</tr>
<tr>
<th>Col 5</th>
<th>Col 5</th>
<th>Col C 85</th>
</tr>
</thead>
<tbody>
<tr>
<td><trim value="Some value a"></trim></td>
<td>Some value b</td>
<td>Some value c</td>
</tr>
</tbody>
</table>
My directive:
angular.module('ui.directives', []).directive('trim', function() {
return {
restrict: 'E',
scope: {
value: '#'
},
template: "{{value | limitTo:6}}"
};
}
);
From within the template I can limit by a constant I define (or pass by, from outside. But I want to change that, to know myself, from within that directive if I should trim the text or not
Yes you can get the parent element using angular's jqlite, a subset of jquery in the link function. The link function is to provide the behavior to your directive, in this function you can get the directive element and modify it at run time according to your need.
angular.directive('myDirective', [function($document) {
return {
restrict:'E',
link: function(scope, element, attribute) {
var parent = element.parent();// will give an array
var parentWidth = parent[0].offsetWidth;
//modify/truncate your attribute.value depending upon the parentWidth.
}
}
}]);