Trying to get a better understanding of ng-if - angularjs

If you take a look at my small code snippet below, what I'm trying to do should be pretty obvious....not every record has this field, so on the ones that don't I want to hide it and the label. What I have here did not work.
<table id="tablepress-1" class="tablepress tablepress-id-1" ng-repeat="agent in vm.agents | orderBy: 'id'" border="0">
<tbody class="row-hover">
<tr class="row-1 odd">
<td class="column-1"><img src="images\{{agent.image}}" alt="" class="aligncenter size-thumbnail wp-image-1116" data-recalc-dims="1" /></td>
<td class="column-2">
{{agent.name}}<br />
Phone: {{agent.phone}}<br />
<p ng-if="{{agent.email}} != ''">E-Mail: {{agent.email}}</p><br />
{{agent.bio}}
</td>
</tr>
</tbody>
</table>
How should I approach this?
Thanks,
newbie

What is given to the ngIf directive will be interpreted already, by being evaluated within the current scope. That is, you do not need to (in fact, you actually have not to) use the {{...}} marker here.
That is, simply using:
<p ng-if="agent.email != ''">E-Mail: {{agent.email}}</p>
... would do wonders. Although, since, when agent.email != '', then basically, agent.email is truth-y, being only evaluated to false in a boolean context if it is undefined or empty (or 0, but I believe that won't happen in your case).
What I'm trying to say is, simply use:
<p ng-if="agent.email">E-Mail: {{agent.email}}</p>
... and you're good to go!

Related

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.

AngularJS: How to call function on last iteration of ng-repeat?

I am trying to figure out how to call a function on the last iteration of an ng-repeat? I am using nested ng-repeats to display results in table format and would like to call a function after all the table cells are loaded.
I was trying to do something like this:
<tr ng-repeat="(rowIndex, rowResults) in chunkedResults">
<td ng-repeat="result in rowResults">
<canvas id="item{{rowIndex}}{{$index}}"></canvas>
<div>Canvas{{rowIndex}}{$index}}</div>
</td>
<div ng-if="$last" ng-init="loadCanvases()"></div>
</tr>
But with nested ng-repeats this does not seem to work. When there is only one ng-repeat present like so:
<tr>
<td ng-repeat="result in rowResults">
<canvas id="item{{$index}}"></canvas>
<div>Canvas{$index}}</div>
<div ng-if="$last" ng-init="loadCanvases()"></div>
</td>
</tr>
Then the function gets called on the last iteration as it should.
Any ideas why?
Add condition in your ng-init
<td ng-repeat="result in rowResults">
<canvas id="item{{$index}}"></canvas>
<div>Canvas{{$index}}</div>
<div ng-if="$last" ng-init="$last?loadCanvases():null"></div>
</td>
You can create a directive and place it in your "last" div :
<td ng-repeat="result in rowResults">
<canvas id="item{{$index}}"></canvas>
<div>Canvas{{$index}}</div>
<div ng-if="$last" data-onlast></div>
</td>
and then execute your own logic in your custom "onlast" directive.
(ng-init is only supposed to be used at the same level as ng-repeat, though you could make it work)
You're probably not approaching your problem the right way.
If you want to execute code once the DOM contains all the list elements (for instance you want to get the pixel height of your element), you can simply do it after a $timeout. This will ensure the previous angular digestion is done and everything is on place in the DOM.
$timeout(function() {
// Here execute anything you want after the list is loaded
});

Only show number bigger than zero with Angular

I dont want to show the price if it's value is 0, only show the name and nothing in price then !
If its greater than 0 then it should show both name and price.
How to do that?
<tr>
<td>{{cars.name}}</td>
<td>{{cars.price}}</td>
</tr>
<tr>
<td> {{cars.name}} </td>
<td><div ng-show="cars.price > 0"> {{cars.price}} </div></td>
</tr>
Edit: if ng-show is evaluated to false it will hide the element by applying display:none; to the element style.
you can also use ng-if which will not render the element at all
Use ng-if if you don't want the cell included in the DOM, use ng-show if you want it to be included but not visible.
<tr>
<td>{{cars.name}}</td>
<td ng-if="cars.price > 0">{{cars.price}}</td>
</tr>
If you're worried about HTML validators
<tr>
<td>{{cars.name}}</td>
<td ng-if="cars.price > 0">{{cars.price}}</td>
</tr>
also works.
This will however probably skew your table a bit, since ng-show still uses display:none;. You can fix that by overriding the .ng-hide CSS class that gets assigned to hidden elements and set it to visibility: hidden; instead.

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.

Resources