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

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!

Related

How can i conditionally display an element using AngularJS

I want to display an element conditionally based on the value of another parameter PaymentTypeid. After setting the condition as below the element Payment Channel is not rendering in the UI:
<tr ng-init="paymentMode='BANK CABS'" ng-if="json.name == 'paymentTypeId' && json.property == '1'">
<td><strong>{{ 'label.heading.paymentchannel' | translate }}:</strong></td>
<td ><span >{{paymentMode}} </span></td>
</tr>
However when i refactor the markup as below the element is showing as :
<tr ng-init="paymentMode='BANK CABS'">
<td><strong>{{ 'label.heading.paymentchannel' | translate }}:</strong></td>
<td ><span >{{paymentMode}} </span></td>
</tr>
PaymentTypeId is in a json array defined as follows in the controller:
scope.details = {};
resourceFactory.auditResource.get({templateResource: routeParams.id}, function (data) {
scope.details = data;
scope.details.paymentMode="";
scope.commandAsJson = data.commandAsJson;
var obj = JSON.parse(scope.commandAsJson);
scope.jsondata = [];
_.each(obj, function (value, key) {
scope.jsondata.push({name: key, property: value});
});
});
In the view PaymentTypeid renders as :
<table class="table" data-ng-show="details.commandAsJson" data-anchor>
<tbody>
<tr data-ng-repeat="json in jsondata">
<td class="width20"><strong> {{json.name}}</strong></td>
<td class="width80">{{json.property}}</td>
</tr>
</tbody>
</table>
Any insight on what i might be getting wrong. Im not entirely sure between using ng-if/ng-show or whether im setting json.property correctly.
Assuming that you have knowledge of scope in AngularJS.
There is a difference between using ng-if and ng-show. Whenever you use ng-if , it creates it own child scope. and you can manage it in custom directive that deals with its child scope (child scope is not available in controller unless you write your code in a way, that will make it available in controller) and you can hack the scope to use it in controller too. But that is not the case in ng-show.
When you use ng-show it will not remove your HTML from the DOM tree but if you use ng-if it will also remove your html from DOM tree. (To assist your confusion which one to use)
You have a scope issue here , if i'm getting it right. Use ng-show and it will work.
<div ng-show="condition">
your html markup
</div>

React.js, handling onMouseOver event

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.

ng-repeat over a div not working

I have used ng-repeat numerous times already in the past, but for some reason I cannot yet understand why it is not on the following situation:
I have an array of objects called registers which I am referencing on the ng-repeat but nothing happens.
I know the array is populated because I have seen it on numerous console.log and because it works if I move the ng-repeat over to the <tbody>
<div ng-repeat = "r in registers">
<!-- START HEADER -->
<tbody class="js-table-sections-header">
<tr>
<td class="text-center">
<i class="fa fa-angle-right"></i>
</td>
<td class="font-w600">Denise Watson</td>
</tr>
</tbody> <!-- END HEADER -->
<tbody>
<tr>
<td class="text-center"></td>
<td>
<!-- Summernote Container -->
<div class="js-summernote-air">
<p>End of air-mode area!</p>
</div>
</td>
</tr>
</tbody>
<!-- END TABLE -->
</div>
I was hoping someone could tell me if there is something I may be ignoring.
Thanks in advance.
I think I just ran into this same problem. It stems from <div> not being a valid elment within a <table>.
I'm guessing that since you have <tbody> there, that there is a <table> tag that was left out of your snippet. <div>s aren't allowed in a table, so the browser moves it before the table. In my situation, doing this, causes the angular scope to change so that there was nothing to iterate over. You can verify this by using the developer tools of your browser.
So, my guess is that you probably want to move the ng-repeat onto the <tbody> or <table> tag.
If you want to use ng-repeat in "div" tag means use "span"
inside div tag. instead of using "table" and its sub attributes..
else use your ng-repeat inside "table" or "thead" or "tr" also
it will iterate rows ...
than only ng-repeat will works.

Ng-click does not work outside of my tr tag AngularJS

I am working on an app and I cant seem to figure out why my ng-click only works inside of my (single) tr tag but as soon as I put it into another tr tag it stop working. Keep in mind it was working before I used the ng-repeat within the first tr tag. Here is what my code looks like, any advice would greatly help!
<table>
<tbody>
<tr>
<td ng-click="commentOpen = !commentOpen">
<div class="iconsize">Comment Closed</div>
</td>
<td ng-click="switchOpen = !switchOpen">
<div class="iconsize">Switch Closed</div>
</td>
</tr>
<tr>
<td>
<div ng-show="commentOpen == true">
<textarea>Comment Open</textarea>
</div>
<div ng-show="switchOpen == true">
<p>Switch On</p>
</div>
</td>
</tr>
</tbody>
</table>
I had the ng-repeat on the tag which was causing my ng-click to not fire. I ended up moving my ng-repeat to the tbody and the ng-click and ng-show started working again.
ngRepeat creates new scopes for its children, it just usually seems like it's accessing the same scope because this new scope inherits from its parent.
Meaning, commentOpen is actually referring to a property on the wrong scope.
Below are three potential ways for you to fix this:
1) controller as, and always refer to the controller you're after by name
2) $parent.commentOpen (Don't do this! It becomes very confusing as you nest)
3) Instead of commentOpen and switchOpen, you can use an Object (e.g. $scope.openControls = { comment: false, switch: false }, and then in the td tags you would write something like ng-click='openControls.comment = !openControls.comment'). This way it's passed inherited by reference (where as a boolean would be by value), and keeps synced.

Angular UI-Router ui-sref ignore some elements

I have an interesting problem with the uiSref directive and I haven't been able to find a solution (well an elegant one anyway) anywhere on the web. Basically I have a requirement from a client to be able to click a row in a table of resources and go to the editing view for that resource. Normally the uiSref directive works beautifully, but the problem resides in the fact that I have a Bootstrap dropdown in the last <td> of the table with a bunch of quick actions in it. The HTML looks something like this:
<table class="table table-bordedered table-hover">
<thead>
<tr>
<td>Name</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="resource in resources" ui-sref="edit({id: resource.id})">
<td ng-bind="resource.name"></td>
<td class="actions-column">
<div class="btn btn-xs btn-default" data-toggle="dropdown">
<i class="fa fa-cog"></i>
</div>
<ul class="dropdown-menu pull-right">
<li>
SOMETHING CRAZY
</li>
</ul>
</td>
</tr>
</tbody>
</table>
The problem is that when I click on the button in the actions column, the uiSref overrides the default action of the dropdown and takes me to the edit page. Now you might be asking yourself "well that's easy, why can't you just stop the propagation of the event!?"... doesn't work. When I add this to the actions column:
<td class="actions-column" ng-click="$event.stopPropagation()">
It kills the functionality of the dropdown menu and nothing shows up. Right now I have a workaround in place where I define an ngClick on the <tr> element that then deciphers where the state should go depending on the element clicked like so:
<tr ng-repeat="resource in resources" ng-click="goToEdit(resource, $event)">
And The JS looks like this:
scope.goToEdit = function(resource, event) {
// if the event.target has parent '.actions-column' or is that column, do nothing else
// invoke $state.go('edit', {id: resource.id})
}
I hate it though and I have a lot of list views like this. All I'm looking for is an elegant and portable solution that hopefully works natively through UI Router like $event.stopPropagation() (Although I've poked through the UI Router source and can't seem to find a workable alternative). Basically I want to have my cake and eat it too. Anyway, it'll be interesting to see what the SO community can come up with or if what I'm asking for is not currently possible. Thanks!
I got it! While looking through the UI Router source some more, it appears that the click event will be ignored if the target attribute is populated on the element that the uiSref resides on. It may not be the most beautiful thing in the world, but it sure is easier than what I was doing before.
NOTE: This only works if you're using the whole jQuery library, not jQLite
So I wrote this directive:
app.directive('uiSrefIgnore', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.on('click', function(e) {
// Find the ui sref parent
var uiSref = elem.parents('[ui-sref]').first();
// Set the target attribute so that the click event is ignored
uiSref.attr({
target: 'true'
});
// Function to remove the target attribute pushed to the bottom
// of the event loop. This allows for a digest cycle to be run
// and the uiSref element will be evaluated while the attribute
// is populated
setTimeout(function() {
uiSref.attr({
target: null
});
}, 0);
});
}
};
});
That way, whenever I want to ignore the javascript event for just the uiSref directive, I can just add this to the html:
<tr ui-sref="edit">
<!-- any other elements -->
<td ui-sref-ignore>The element I care about</td>
</tr>
BOOM! Let me know what you guys think about the implications of this.

Resources