ng-repeat not compiling directive inside table row - html

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.

Related

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;

Angular checkbox gets updated even though ngModel doesn't

I'm working on a shift arrangement app. In it I'm trying to create two tables that show which possible shifts each user has selected.
Both tables display the same data, but arrange it differently. Each table cell has a number of check-boxes that display the possible shifts for each person (in table 1) or the possible people for a shift (in table 2). A checkbox from table 1 that displays shift A option for person X will have the same data-bind as its equivalent checkbox in table 2, which displays person X option for shift A.
The purpose of this is to update the equivalent data in both tables simultaneously when the user couples a person with a shift. The problem: when a checkbox in table 1 is checked/unchecked, all of the check-boxes in table 2 gets checked/unchecked, as shown below:
Here is my template:
<div class="table-container" dir="ltr">
<h3>People</h3>
<table>
<thead>
<th>Name</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let user of userPreferences">
<td>{{user.name}}</td>
<td>
<div *ngFor="let selection of userYesses[user.name]">
<mat-checkbox class="option-checkbox" dir="ltr" [(ngModel)]="selection.isSelected" name="usc">{{selection.option}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="table-container" dir="ltr">
<h3>Shifts</h3>
<table>
<thead>
<th>Time</th>
<th>Options</th>
</thead>
<tbody>
<tr *ngFor="let shift of totalShifts">
<td dir="ltr">{{shift.time}}</td>
<td>
<div *ngFor="let selection of shiftYesses[shift.time]">
<mat-checkbox class="option-checkbox" [(ngModel)]="selection.isSelected" name="syc">{{selection.name}}</mat-checkbox>
</div>
</td>
</tr>
</tbody>
</table>
</div>
And here is relevant component code:
this.userPreferences.forEach(u => {
this.userYesses[u.name] = [];
u.preferences.shifts.forEach(week => {
week.forEach(day => {
if (!day.shifts) return;
day.shifts.forEach(shift => {
if (!this.shiftYesses[`${day.date} ${shift.time}`]) this.shiftYesses[`${day.date} ${shift.time}`] = [];
if (shift.isSelected) {
let selection = new Selection(`${day.date} ${shift.time}`, u.name);
this.userYesses[u.name].push(selection);
this.shiftYesses[`${day.date} ${shift.time}`].push(selection);
}
});
});
});
});
The code seems alright to me, am I missing anything? Maybe it's a bug in Angular?
Thanks in advance!
In case anyone else experiences this issue -
After a few days of struggling with this, I stumbled upon this issue from Angular's git - https://github.com/angular/angular/issues/9230
I've read the following in kara's answer:
In the case that you don't want to register a form control, you currently have a few options:
1 - Use ngModel outside the context of a form tag. This will never throw.
<input [(ngModel)]="person.food">
After reading this, I switched the <form> tag into a <div> and everything works as expected now.

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

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

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');
},
...

Hyperlinks in one column, show contents in the second column?

So I have a table with two columns and one row. The left column has a list of hyperlinks. I would like the right column to display the contents of those hyperlinks when clicked.
The end result would have the left column still showing all the hyperlinks whilst the right column shows the corresponding contents. How would I go about doing this?
Here's some of the code:
<body>
<table width = "70%">
<col width = "20%">
<tr>
<td><big><strong>Home</strong></big>
<br/>
<big><strong>About myself</strong></big>
<br/>
<big><strong>My hobby</strong></big>
<br/>
<big><strong>My CV</strong></big>
<br/>
<big><strong>Links</strong></big>
</td>
<td valign ="top"> </td>
</tr>
</table>
There may be a simpler way, but I would use a fade-toggle using Javscript.
Have a div on the right with the content, which once the hyperlink is clicked will appear.
$(document).ready(
function() {
$("#div").click(function(e) {
e.preventDefault();
$("#link").fadeToggle(1000);
});
});