How do I place a react link on tds of a table? - reactjs

I want to have all the td's from firstName to email be clickable to link to that specific contact. Do I have to put a Link wrapper on each div? Even if I do, I want the Link to wrap around the entire td, not just the text within it so that the user can click on any part of the td rather than the text itself.
<tr key={index}>
<td><Link to={`/${contact.id}`}><div>{contact.firstName}</div></Link></td>
<td>{contact.lastName}</td>
<td>{contact.city}</td>
<td>{contact.phone}</td>
<td>{contact.email}</td>
<td><input type="checkbox" value="readOnly" checked={that.state.deleteList.includes(contact.id)} onClick={that.addToDeleteList.bind(that, contact.id)}/></td>
</tr>

For link part you are doing it correctly. Just remove <div> from Link tag.
To make whole table cell clickable irrespective of content within it set display of Link to block via css or inlinke css.
e.g.
display: block
Here is CSS for the same.
td a {
display:block;
width:100%;
}

Related

Show/Hide all with show/hide sections inside angularjs

I need to have an overall Show/Hide click to show or hide all the detail divs of a list of "panels" of data. Also within each panel, there is a Show/Hide click to individually show or hide that div of data.
I think that if the overall show/hide is clicked that the individual click values should be set equal to overall value when clicked. That way if the individual ones are changed, they are all set to show or hide when the main one is clicked.
This is how I tried to do that:
<div>- Hide All Details / + Show All</div>
<div class="tender-list" ng-repeat="row in tenders" ng-include="'tender/tender_panel.html'"></div>
Where the hide/show part of tender_panel.html is here:
<div>- Hide Details</div>
<div class="tender-details" ng-hide="hideDetails">
<table width="100%" id="tender-bottom-table">
<tbody>
...
</tbody>
</table>
</div>
There is another table above the tender-bottom-table. Plus a another table after.
What is happening is that it works fine when initially loaded. The Hide All/Show All works. Then I click on the individual show/hides and they work. But then the All Show/All Hide no longer works and I don't see how clicking the individual links breaks things.
This app is Symfony2 with Angular and Bootstrap.
Any help would be greatly appreciated.
one thing you could try is to have a property flag in each tenders item that sets if it's shown/hidden and show the individual item based on if hideAllDetails + their flag is true:
<div>- <a href='#' ng-click="hideAllDetails = ! hideAllDetails;">Hide All
Details / + Show All</a></div>
<div class="tender-list" ng-repeat="row in tenders" ng-
include="'tender/tender_panel.html'"></div>
tender_panel.html:
<div>- <a href='#' ng-click="row.hideDetails = ! row.hideDetails">Hide
Details</a></div>
<div class="tender-details" ng-hide="hideDetails || hideAllDetails">
<table width="100%" id="tender-bottom-table">
<tbody>
...
</tbody>
</table>
</div>

Table styling with LESS

This question is about styling a table which is created inside an AngularJS directive. I have an array of objects passed to the directive from HTML file. The directive creates a table and shows each object of the array in a row.
Now my question: There is a self-defined JSON field in each object called name. Styling is done by LESS technology and I want to have a thick separating line behind each row when 'name == david'. Please consider this condition can be different for example when 'rowID%3 ==0' and etc. My general question is how can I access this objects in LESS file and how can I make conditional styling inside LESS.
I'm making a lot of assumptions since you didn't include any code or markup, but in Angular this is a very basic, simple problem, and is independent of whether you are using LESS, Sass, or just plain CSS:
<table>
<thead>
<tr>
<th>Col 1</th>
<th>Col 2</th>
<th>Col 3</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in vm.items track by $index" ng-class="{'thick-separator': isNameDavid(item) || $index%3 == 0}">
<td>{{item.propOne}}</td>
<td>{{item.propTwo}}</td>
<td>{{item.propThree}}</td>
</tr>
</tbody>
</table>
In your controller:
$scope.isNameDavid = function(item) {
return item.name == 'david';
};
Using the ngClass directive and the $index scope variable that is introduced by the ngRepeat directive, you can easily assign a thick-separator class to table rows, conditionally.
Now, it makes no difference if you are using LESS, Sass, or plain CSS:
.thick-seperator {
border-top: 5px solid black;
}
If, however, you are trying to say that you can't change the Angular code and you need to be able to style purely with LESS, then you can style using attribute and nth-child selectors. Note that these are available in plain CSS and LESS is not needed:
table tbody tr:nth-child(3n+3), table tbody tr[data-name="david"] {
border-top: 5px solid black;
}

onclick on hyperlink should add a div horizontally using angularjs

My html:
<div id="contentDiv">
<div id="headerDiv" ><div id="titleDiv"> Queries</div></div>
<div id="valuesDiv" ><div id="yearDiv"> 2015</div></div>
<div id="graphDiv" ><div id="chartDiv">graph</div></div>
</div>
Like this div, I have another div but the content in the div is different.
How to add a new div horizontally when I click on hyperlink using angularjs?
How can I do this? please help me out regarding this
Looks like what you need is a two way binding with the ng-model directive. So the idea would be that you bind the new div to a variable in your scope which is initially in an empty or undefined state (for example, there are better ways). When the hyperlink is clicked it calls the function specified by an ng-click directive which will fill your bound object, which in turn will cause the new div to be rendered.
EDIT:
Based on your comments here is a simple example.
HTML page:
<div id="newDiv" ng-repeat="item in items">
<!-- Div content -->
<!-- example -->
<input type="text" ng-model="item.name">
</div>
<input type="button" ng-click="addItem()">
Controller:
$scope.items=[];
$scope.addItem = function() {
var newItem = {};
newItem.name = "new item name";
$scope.items.push(newItem);
}
What's happening here is the data for each div is stored in an array of objects. The ng-repeat directive will repeat the div for each object in the array. You can then fill the elements in the div using the object. Adding a new div is as simple as adding a new item to the array and angular will take care of the rest for you. Please note that I have not tested this example, but hopefully it's enough to point you in the right direction.
RE aligning the divs horizontally, this will be done with CSS, using the inline-block display mode. So you could give the div a class of, for example, "horizontalDiv" and add the following class to your CSS file:
.horizontalDiv {
display: inline-block;
}

Angular ng-class setting proper class (confirmed in page source) but won't apply styles

Yes...it's tabular data.
So, the question title explains most of what is going on but I'll provide a few more specifics: I have a model on my controller that contains properties "Name" and "Value"(with possibilities"GOOD" and "BAD")
I have 2 classes defined in my SCSS file to provide styles for "valid" and "invalid" values.
SCSS pseudo.
&[class *= "Foo"]
{
color: green;
}
&[class *= "Bar"]
{
color: red;
}
Markup
<ul ng-controller="thingsController">
<li ng-repeat="thing in things">
<table >
<tr >
<td>{{thing.name}}</td>
<td ng-class="{'Foo' : true}">{{thing.value}}</td>
</tr>
</table>
</li>
</ul>
Ok, so the crux of this:
If I use:
<td class="Foo">{{thing.value}}</td>
it renders value with green text color.
If I use:
<td class="Bar">{{thing.value}}</td>
it renders value with red text color.
HOWEVER,
If I use:
<td ng-class="{'Foo':true}">{{thing.value}}</td>
It renders value with black (default) colored text.
(Same for Bar)
When I inspect my element in Chrome Dev Tools, I see
<td ng-class="{'Foo':true" class="ng-binding Foo">GOOD</td>
but if I inspect the styles tab, the styles within Foo have not been applied to my element...it's nowhere in my cascade.
Can anyone tell what's up with that?
I've found the cause. It is related to using regex selectors to build a block__element--modifier css structure.
ng-class apparently does not respect the "begins with" css selector.
[class ^= "block"]
{
&[class *= "__element"]
{
&[class *= "--modifier"]
{
}
}
}
I had to change the initial [class ^= "block"] to [class *= "block"]
which is absolute crap...but ng-class was able to do what it is supposed to do.
Edit
The reason that the "Begins With" css selector cannot be used with ng-class is that "begins with" performs a whole string comparison on the value of class.
ng-binding
gets prepended by Angular to the classes that get applied through the ng-class directive, so the class becomes
class="ng-binding foo"
...which does not begin with foo.

ng-grid hiding bootstrap styled dropdowns

I am upgrading a table form. Each row in the table has several elements, including two drop downs in specific columns for each row. I have upgraded the table to ng-grid and upgraded the drop-downs from plain select widgets to styled bootstrap drop-down elements to match the others on the site. The essential problem I am having is that the CSS layout of ng-grid causes the actual drop down menu to be put behind the cell below, and so not visible. Examining the elements shows that they are actually being rendered, have proper height, width and content, but are merely displayed behind the content in the other cell. I have tried disabling the CSS overflow: hidden on the desired cells, but it seems this property is also set for the entire grid and turning it off at that level totally breaks the grid layout. I have a working workaround, but it makes me want to take a shower and I am sure there is a more elegant way to do this:
1) put a cell template in for just the visible part, including an ng-click call passing the column (Coffeescript):
{field: "type",
displayName: "Type",
width: 155,
original_width: 155,
pinned: false,
cellClass: "type_col",
headerClass: "type_col",
cellTemplate: """<div ng-click="editor.activeCol(col)" class="btn-group">
<button ng-show="row.entity[col.field]" style="width: 125px"
class="btn dropdown-toggle blk-txt" href="#">
{{row.entity[col.field]}}</button><button class="btn">
<span class="caret"></span></button></div>"""
},
2) Put a select row callback to a different method:
multiSelect: false,
enableRowSelection: true,
afterSelectionChange: angular.bind(#, selectFunc),
3) Have a totally separate angular template of the drop-down options that is classed to always be shown open for bootstrap, but has both a ng-show and ng-style elements to allow my code to change its visibility and exact location:
<div ng-show="editor.utilization" ng-style="editor.dropdown_style">
<div class="btn-group editor-widget open">
<ul class="dropdown-menu">
<li ng-click="editor.selectUtil('heavy')">Heavy</li>
<li ng-click="editor.selectUtil('medium')">Medium</li>
<li ng-click="editor.selectUtil('light')">Light</li>
</ul>
</div>
</div>
When a user clicks on the (apparent) drop down, the following happens:
1) ng-click event delivers the column to the class, this is stored
2) row select (afterSelectionChange) callback triggers with the row and is able to get the column from the previous call, with both the row and column we now know the actual cell
3) The exact screen position of the cell in question is grabbed and the drop-down selections template is made visible directly below the clicked cell, making the illusion of a normal drop-down operation.
This is a long explanation, but wanted to give the background of what I have tried, to show that I am looking for a simpler (hopefully MUCH simpler) way to just include styled bootstrap drop-down widgets in ng-grid cells. The entire thrust of this project is to style and beautify already working forms so solutions that work only by cutting style for pure functionality don't really serve the purpose.
This is how I solved it. I have a cell in the ng-grid and in the cell i have a glyphicon arrow down. When I click it I want the dropdown toggle to show. With the CSS I got what I wanted. However, I have many cells with arrows and thus I had to change the css-style "left" dynamically. I do this with my javascript.
Hope it helps!
Cell Template:
<div class="ngCellText" ng-class="col.colIndex()" class="dropdown">
<span ng-cell-text>{{row.getProperty(col.field)}}</span>
<a class="dropdown-toggle" ng-click="setXchords($event)">
<i class="glyphicon glyphicon-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li ng-repeat="choice in editableItems">
<a>{{choice}}</a>
</li>
</ul>
</div>
CSS:
.dropdown-menu {
position: fixed;
top: inherit;
left: 85px;
}
JavaScript:
$scope.setXchords = function(e) {
var elem = angular.element(e.currentTarget);
$(elem).next().css('left', e.clientX).css('top', e.clientY);
};
In order to show regular dropdowns, I added this css:
.ngCell { overflow: visible; }
In order to get multiselects to appear, I needed to add a class (I used "field-multiselect") to an editableCellTemplate and then add the following css to the class:
.field-multiselect {
position: relative;
overflow: visible;
z-index: 888; }
This worked for me! (Finally, after quite a bit of trial and error!)

Resources