React.js, handling onMouseOver event - reactjs

being a noob in React I'm facing a problem: the component returns a simple nested table, so each cell of the 'big-table-id' contains another small table 'small-table-id'.
Thing is that every time the mouseover event occurs I'm always getting the 'small-cell-*' as target.id, even if the event handler is referenced in the parent (big) table. Is there any way to get the parent table kinda 'non-transparent' so that I could receive 'big-table-cell-1' or 'small-table-id'?
(using Rails with 'react-rails' gem)
var Tables = React.createClass({
handleMouseOver: function(e){
console.log(e.target.id)
},
render: function(){
return (
<table id='big-table-id' onMouseOver={this.handleMouseOver}>
<tr>
<td id='big-table-cell-1'>
<table id='small-table-id'>
<tr>
<td id='small-cell-1>
text 1
</td>
<td id='small-cell-2'>
text 2
</td>
</tr>
</table>
</td>
</tr>
</table>
)
}
});

The DOM lets you select an elements child and parent nodes with methods like firstChild and parentElement. You should look into those.
Edit: also not sure if this would work but you could try wrapping the big table in a div and setting the callback there and seeing what it references.

Related

reactjs table render - how to handle empty rows rendering for tbody

I am very new to ReactJS and playing around to learn its tricks of the trade. I am trying to create a simple table with thead and tbody.
my code looks as below:
/**
* creates a HTML table to show requirements
**/
var ReqTable = React.createClass({
render: function() {
var rows = [];
rows = this.props.data.map(function(row) {
return ( <ReqRow row={row} />);
});
return(
<table className="reqTable table table-bordered table-striped">
<thead>
<tr>
<th>REQ #</th>
<th>Short Desc</th>
<th>Long Description</th>
</tr>
</thead>
<tbody> {rows} </tbody>
</table>
);
}
});
I am using ajax call to get the rows and render this table. This works fine overall, but gives a warning in the browser console, indicating that you cannot add a span inside a tbody.
I am sure I am not adding a span. But what I believe is that when there are no rows (when render is first time called), it seems reactJS is trying to render a span inside the tbody.
So, should I put an if check here to avoid rendering a span? Finally what is the correct way to render a empty set of rows in tbody?
Your issue is that you have space characters as children of your tbody element, before and after your rows array:
<tbody> {rows} </tbody>
Compiles to:
React.createElement("tbody", null, " ", rows, " ");
Because of DOM limitations, when a DOM component has more than one child, React wraps all its text children within <span> elements. So the above JSX is equivalent to:
<tbody><span> </span>{rows}<span> </span></tbody>
To fix this, just remove the extraneous characters:
<tbody>{rows}</tbody>

ui.bootstrap.collapse - one collapse for each row in a table column - open only the collapse which has been clicked (not all of them)

I'm using ui-bootstrap.collapse inside a table with dynamic data from a JSON API. Two of the multiple columns contain collapsed partials for each of its rows.
When I'm clicking on one of the icons to toggle that particular partial, every partial of the entire column open up.
Same issue when I'm trying to close the partial again - any of the icons work (not only the one of that particular partial).
I'm suspecting that I got to add a unique id or something like this to each of the partials to make one only that particular one pop up. But I'm not able to get this working.
Can any one point me in the right direction please?
Here is some of my code (I replaced the dynamic data with static data to make it simpler:
...
<tbody ng-repeat="url in urls">
<tr>
<td>{{url.url}}<span class="pull-right" ng-click="toggleUrl()">▼</span></td>
<td>{{url.title}}</td>
<td>{{url.traffic}}<span class="pull-right" ng-click="toggleTraffic()">▼</span></td>
</tr>
<!-- urlCollapsed -->
<tr collapse="!urlCollapsed">
<td colspan="4" style="background-color: pink">
</td>
</tr>
...
and a working plunker with the entire code: http://plnkr.co/edit/e4UldAFjjIr26Il73C88?p=preview
You need to pass url or some unique field to toggleUrl() method and then at the method make specific variable for each roe partial nd make them true. Accordingly you'll have to mak specific partial for each nd shoe them accordingly on ng-show.
Something like this
$scope.toggleUrl = function (url) {
if (url === '/1') {
$scope.url1Collapsed = !$scope.url1Collapsed;
} else {
$scope.urlCollapsed = !$scope.urlCollapsed;
}
};
and on page
<tr collapse="!url1Collapsed">
<td colspan="4" style="background-color: pink">partial 1</td>
</tr>
<tr collapse="!urlCollapsed">
<td colspan="4" style="background-color: pink"> partial 0</td>
</tr>

Smart Tables Pagination Wont Work With Server Side Filtering

I have a smart table that I am working on in AngularJS. The table uses a custom pipe in order to search and sort its data. I also require that the table has working pagination, along with a drop down box so you can select the number of rows to be displayed (think datatables).
For searching and sorting, the custom pipe fires off my ajax requests without a problem. However, when I click on any of the page numbers or change the number of rows to show, the pipe is NOT fired.
The page numbers seem to be set to call setPage(page) (this is set by the st-pagination directive) but nothing happens - and no errors are thrown.
How do I get the custom pipe to fire upon changes to the number of rows displayed or when a page # is clicked in the pagination controls?
Here is my HTML:
<table class="table table-striped table-bordered" st-table="leadsCollection" st-safe-src="leads" st-pipe="serverFilter">
...
<tbody>
<tr data-toggle="modal" data-target="#modal-source" ng-repeat="source in leadsCollection" ng-click="rowClick($index);">
<td>{{source.leaddate}}</td>
<td>{{(source.distance > 100) ? 'Long Distance' : 'Local'}}</td>
<td>{{source.origin_city}}, {{source.origin_state}}</td>
<td>{{source.destination_city}}, {{source.destination_state}}</td>
<td>{{source.est_move_date}}</td>
<td>{{source.distance}} mi</td>
<td>{{source.number_bedrooms}} br</td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="8">
<div class="form-group col-md-1">
<label>Show:</label> <select class="form-control" ng-model="itemsByPage"><option value="10">10</option><option value="25">25</option><option value="50">50</option><option value="100">100</option></select>
</div>
<div class="pull-right" st-pagination="" st-items-by-page="itemsByPage"></div>
</td>
</tr>
</tfoot>
</table>
And here is the controller:
.controller('Leads', function ($scope, $http) {
$scope.leads = [];
$scope.leadsCollection = [].concat($scope.leads);
$scope.itemsByPage = "10";
$scope.rowClick = function (idx)
{
$scope.editor = $scope.leads[idx];
}
$scope.serverFilter = function(tablestate)
{
$http.post("/portal/api/loadleads",tablestate).success(function(response){
console.log(response);
$scope.leads = response;
$scope.leadsCollection = [].concat($scope.leads);
});
}
})
In order to get smart tables to fire the filters off, you have to set the numberofpages on data load. To get the above filter to work simply add:
tablestate.pagination.numberOfPages = response.totalPages;
Smart Tables seems to require this to be set in order for it to properly bind the events.

How to get Angular to update the Ui from within the controller

I have the following html.
<div ng-controller="CustCtrl">
<table class="table table-condensed">
<thead>
etc.
</thead>
<tbody>
<tr ng-repeat="customer in customers" data-cust-id="{{customer.Id}}">
<td>
<button ng-model="Id" tracking-{{customer.Tracking}} ng-click="startTrackingCustById(customer.Id)">
</button>
</td>
etc.
</tr>
</tbody>
</table>
So the button has a class that is databound to the customer.Tracking value which is either true or false. When the button is clicked the startTrackingCustById() method is successfully called and the customer object in the customers object is successfully changed like customer.Tracking = true.
But the buttons class is not updated. What am I missing?
Look at using ng-class . For a boolean value in scope you would use:
ng-class="{'classNameToAddIfTrue':customer.Tracking}"
In the CustCtrl I wrapped the call that updated the customers array like this
$scope.$apply($scope.customers[i].Tracking = true);
Based on the suggestion in an answer I will link to when I find it that basically said "If you are having trouble updating the view you most likely need to use $scope.$apply
So that get's it to work. Now I need to figure out why and how.

Underscore.js templates in backbone.js adding a div around a tr

I am using underscore.js's templating capabilities from backbone.js, I have the following template that I define in my page like this:
<script type="text/template" id="businessunit_template">
<tr data-uid="{{Uid}}">
<td class="first"><span>{{Name}}</span></td>
<td class="{{StatusClass}} tac">{{OverallScore}}%</td>
<td>
<a class="impactanalysis individualBu" href="#"> </a>
</td>
</tr>
</script>
I am attaching the trs to the tbody element of following table:
<table class="listing">
<thead>
<tr>
<th class="first">Business Units</th>
<th>BCMS<br />Status</th>
<th>View</th>
</tr>
</thead>
<tbody id="reportBusinessUnits"></tbody>
</table>
My individual backbone view that renders the tr looks like this:
class ReportBusinessUnitView extends MIBaseView
initialize: (options) ->
#vent = options.vent
#template = _.template($('#businessunit_template').html())
events:
"click .individualBu": "showBusinessUnitDetail"
showBusinessUnitDetail: (e) =>
e.preventDefault()
self = #
#vent.trigger('management:showbusinessunitdeail', #model)
render: =>
$(#el).html(#template(#model.toJSON()))
#
The problem is, the rendered output has a div around the tr and I have no idea where it is coming from:
<div>
<tr data-uid="a5e3c218-1ca4-4806-b27e-24a25ed83ab6">
<td class="first"><span>Central Networks</span></td>
<td class="red tac">4%</td>
<td>
<a class="impactanalysis individualBu" href="#"> </a>
</td>
</tr>
</div>
I just cannot see what I am doing wrong. Has anybody any idea where this could be coming from?
That looks very much like the kind of faulty DOM fragment you get when you haven't declared the .el attribute in a View correctly. I'd put a breakpoint/debugger statement in ReportBusinessUnitView.render() and inspect the value of the this.el attribute from there. (View.el docs).
Also, check your code:
Have you declared an .el property? (in MIBaseView for example)
Does it hit the right DOM node?
If not, Backbone auto creates the DIV node for you, which can be confusing.
The inclusion of a default DIV tag to surround the template is, I believe, a safety measure. This gives a parent tag to which the view's events are attached. That way event propagation will work as expected. As well, if you discard a view and remove the inserted HTML all events will go with it allowing the garbage collector to do its job.
I recently had considerable grief because I set the .el to the static HTML parent node (in order to prevent the default DIV from being added). Since it remained even after my dynamic HTML was replaced the events were still around responding to actions and creating general chaos!

Resources