What's the difference between `ng-show` and `ng-hide`? - angularjs

These attributes are both given either a true or false value, so what difference is there between them? It would make sense if there weren't values for them.
Am I missing something?

With ng-show the element is shown if the expression is true, it will hide if it is false
On the other hand with ng-hide the element is hidden if the expression is true and it will be shown if it is false.
Just two sides of the same coin.

On a project I was working on before, I found having the option of both ng-show and ng-hide useful. The reason being is because I had a link in my navbar that was only supposed to show if the user was on a specific view. Here is that scenario:
<li ng-hide="isActive('/about') || isActive('/contact')" ng-class="{ 'vert-nav-active': isActive('/investigator')}" class="top-buffer">
Investigator Portal
</li>
Now, you might say, well you could just make the isActive('/about') || isActive('/contact') return the opposite Boolean and change the ng-hide to ng-show and every thing will stay the same but as you can see I'm also using this function to determine which link I'm on. If I reverse this logic, it will look like I'm on every link except the actual link I'm on. Granted I could write another function for the ng-show but I like reusing code that's already there.

Also worth mentioning is ng-if which takes a boolean expression just like ng-show and ng-hide but rather than just showing/hiding the elements depending on the expression, it completely removed the element from the DOM if the expression is false and put the element back in the DOM if the expression becomes true

i have a good scenario, let say you want to show one attribute or another depending on a validation, but not both, so using both ng-show and ng-hide like this:
<div ng-show="validation"></div>
<div ng-hide="validation"></div>
if the validation is true it would show the first div, but if it is false it would show the second div...
this can be done in many more ways but is a cleaver solution for a tricky problem :D

ng-show will only display the element IF the expression is true...
<span ng-show="true">Will Show </span>
<span ng-show="false">Will not Show </span>
ng-hide will not display the element IF the expression is true, but will display if the expression is false.
<span ng-hide="true">Will not display</span>
<span ng-hide="false">Will display</span>

Related

ng-show doesn't show the Div even when my Array length evaluates to Zero

<div class="emptyMessage" ng-show="{{ToBuy.Items.length}}==0" > Everything is bought! {{ToBuy.Items.length}} </div>
I wanted the above Div tag to not show when my ToBuy.Items array has some elements in it. The Div tag should appear only when there are no Items in ToBuy.Items array has no elements.
When I removed all elements from the array (Tobuy.Items), the expression simply shows ng-show="0==0" and the Div Tag doesn't show up on the web page.
Any help greatly appreciated.
ngShow expects an expression, so you do not want to put curly braces in it. Try the following:
ng-show='ToBuy.Items.length == 0'
I'd recommend making this expression a property on your controller instead of checking ToBuy.Items.length == 0. Business logic belongs in the controller, not in the view.
Remove the expression inside the ng-show,
<div ng-controller="MyCtrl">
<div ng-show="ToBuy.Items==0"> Everything is bought! {{ToBuy.Items.length}} </div>
</div>
DEMO
Try to use ng-hide
ng-hide='ToBuy.Items.length'
or
ng-hide='ToBuy.Items'
both should work i think.

Possible to have Angular ng-if with multiple conditions, some bound once, some two-way?

My question is not whether or not you can use multiple conditions in ng-if, but rather whether or not it's possible to have ng-if with only some conditions bound once, while others watch for updates?
As a simple example, if I want to bind the name once, but have a toggle state property that I want to watch for updates: <span ng-if="::page.name === 'something' && page.viewEnabled">Correct page, and the view is enabled!</span>
I would expect that a toggle to page.viewEnabled assuming it's a boolean, would cause the span to disappear. That does not appear to be the case (using Angular 1.3.11).
Does the one-time binding on ::page.name setup the entire expression as being bound once?
Thanks in advance!
EDIT: What I'm curious about is if you have multiple conditions in the same ng-if, one being bound once, while another is not. What I'm seeing is that if you have one that is bound once, the other changing will not affect the ng-if statement.
I just tested this out, and can confirm that you can in fact bind-once to an ngIf statement. Consider the following example:
https://plnkr.co/edit/m32BBBYlNffxTfggb33g?p=preview
Say your UI is programmatically updating an array of fruits, and let's say we have two ngIf expressions: one uses bind-once, the other is bound normally (i.e twice):
<div ng-if="::fruits.length > 3">More than three fruits!</div>
<div ng-if="fruits.length > 3">More than three fruits!</div>
If we begin adding to this array, we'll note that only the second ngIf expression is triggered when the condition is met:
UPDATE
So it looks as though the original question was more geared toward putting two (2) expressions in an ngIf, but where one expression utilizes bind-once. And interestingly enough, neither of the statements fire (see below), which is a bit surprising, which would seem to indicate you cannot combine one and two-way bound expressions. In the first ngIf, I would have expected the very first condition to have been evaluated truthfully, then short-circuit since it doesn't need to evaluate the second expression, which happens to be bound once. But that doesn't seem to be the case.
Plunkr has been updated.
<div ng-if="fruits.length > 3 || ::fruits.length > 3">1.) More than three fruits!</div>
<div ng-if="::fruits.length > 3 || fruits.length > 3">2.) More than three fruits!</div>

Generate dynamic expressions in ng-repeat

I have a ngRepeat element that has a delete button that triggers a confirmation message. I'm trying to make the confirmation message show with a dynamic expression like so:
<div ng-repeat="item in items">
<a ng-click="delete(item_id)"></a>
<span ng-show="{{item._id}}_delete">Are you sure you want to delete your review? </span>
</div>
I'm not sure if this is the right way to create dynamic expressions, but this is the only way I can get the expression to at least generate in html.
But I am getting this error for all the repeated items (with different item ids in each error):
Error: [$parse:syntax] Syntax Error: Token 'cb0a2a73ede6e3a9d7a58_delete' is an unexpected token at column 4 of the expression [543cb0a2a73ede6e3a9d7a58_delete] starting at [cb0a2a73ede6e3a9d7a58_delete].
^ the outputted item._id for that item is 543cb0a2a73ede6e3a9d7a58 for example.
Angular is expecting an expression there that returns true or false for ng-show. So just rendering a String won't really help. You could either define a controller function that resolves to true or false or just write the expression inline, like ng-show="item.id === 2".
But it seems that you want a confirmation dialog before deleting, in that case you should write a custom directive that intercepts the click action before executing it (unfortunately there is no such thing as ng-confirm in Angular built-in).
Here is an example of such a directive: https://gist.github.com/asafge/7430497
If you simply want to toggle a message to the user, you could simply make your span dependant on a scope variable that gets toggled, like so:
<a ng-click="delete(item_id); showDelete=!showDelete">item</a>
<span ng-show="showDelete">Are you sure you want to delete your review? </span>
JSFiddle here.
However, you probably want to wrap it all up into a directive like #frank blizzard mentioned.
try this one :)
AH, if item._id starts with a number it will get a error
Variable names must begin with a letter
link
so ng-show bound to a variable in the scope and it is dynamically creating. a_delete,b_delete will work fine but if it generate like 1_delete,2_delete it will result a error because those are starts with a number.
In your case item._id starts with number like 543cb0a2a73ede6e3a9d7a58 as you mentioned in you question. so ng-show ends with something like ng-show="543cb0a2a73ede6e3a9d7a58_delete". That should get a error because of violation of naming-conventions.

elasticui - Triggering sort with ng-click only firing on first click

I'm trying to make the sort functionality work by creating two buttons: relevance and date.
I've set it up the following way:
<div ng-init="sort=false">
<a ng-click="sort=true">Date</a>
<a ng-click="sort=false">Relevance</a>
then on the container with the results:
<div eui-sort="ejs.Sort('post_date').order('desc')" eui-enabled="sort" >
The value set with ng-init properly affects the initial sort order and when I click date the list sorts as intended, but when I click relevance the list does not re-sort back as if eui-enabled was set to false.
I'm guessing underformed knowledge of Angular is causing me to oversimplify this. Any advice?
I suspect you're running into the AngularJS dot-problem, i.e.: the sort. A way to circumvent this is modifying sorting.sort within the eui-sort scope:
<div eui-sort="ejs.Sort('post_date').order('desc')" eui-enabled="true">
<a ng-click="sorting.enabled=true">Date</a>
<a ng-click="sorting.enabled=false">Relevance</a>
</div>
In this example, eui-enabled is only used for initialization since the value (true) doesn't change. Note that to reference the "sorting: object you must be inside the scope of the eui-sort (i.e.: inside the div)

What is the best way to conditionally apply attributes in AngularJS?

I need to be able to add for example "contenteditable" to elements, based on a boolean variable on scope.
Example use:
<h1 attrs="{'contenteditable=\"true\"': editMode}">{{content.title}}</h1>
Would result in contenteditable=true being added to the element if $scope.editMode was set to true.
Is there some easy way to implement this ng-class like attribute behavior? I'm considering writing a directive and sharing if not.
Edit:
I can see that there seems to be some similarities between my proposed attrs directive and ng-bind-attrs, but it was removed in 1.0.0.rc3, why so?
I am using the following to conditionally set the class attr when ng-class can't be used (for example when styling SVG):
ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"
The same approach should work for other attribute types.
(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)
You can prefix attributes with ng-attr to eval an Angular expression. When the result of the expressions undefined this removes the value from the attribute.
<a ng-attr-href="{{value || undefined}}">Hello World</a>
Will produce (when value is false)
<a ng-attr-href="{{value || undefined}}" href>Hello World</a>
So don't use false because that will produce the word "false" as the value.
<a ng-attr-href="{{value || false}}" href="false">Hello World</a>
When using this trick in a directive. The attributes for the directive will be false if they are missing a value.
For example, the above would be false.
function post($scope, $el, $attr) {
var url = $attr['href'] || false;
alert(url === false);
}
I got this working by hard setting the attribute. And controlling the attribute applicability using the boolean value for the attribute.
Here is the code snippet:
<div contenteditable="{{ condition ? 'true' : 'false'}}"></div>
In the latest version of Angular (1.1.5), they have included a conditional directive called ngIf. It is different from ngShow and ngHide in that the elements aren't hidden, but not included in the DOM at all. They are very useful for components which are costly to create but aren't used:
<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>
To get an attribute to show a specific value based on a boolean check, or be omitted entirely if the boolean check failed, I used the following:
ng-attr-example="{{params.type == 'test' ? 'itWasTest' : undefined }}"
Example usage:
<div ng-attr-class="{{params.type == 'test' ? 'itWasTest' : undefined }}">
Would output <div class="itWasTest"> or <div> based on the value of params.type
<h1 ng-attr-contenteditable="{{isTrue || undefined }}">{{content.title}}</h1>
will produce when isTrue=true :
<h1 contenteditable="true">{{content.title}}</h1>
and when isTrue=false :
<h1>{{content.title}}</h1>
Regarding the accepted solution, the one posted by Ashley Davis, the method described still prints the attribute in the DOM, regardless of the fact that the value it has been assigned is undefined.
For example, on an input field setup with both an ng-model and a value attribute:
<input type="text" name="myInput" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
Regardless of what's behind myValue, the value attribute still gets printed in the DOM, thus, interpreted. Ng-model then, becomes overridden.
A bit unpleasant, but using ng-if does the trick:
<input type="text" name="myInput" data-ng-if="value" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
<input type="text" name="myInput" data-ng-if="!value" data-ng-model="myModel" />
I would recommend using a more detailed check inside the ng-if directives :)
Also you can use an expression like this:
<h1 ng-attr-contenteditable="{{ editMode ? true : false }}"></h1>
I actually wrote a patch to do this a few months ago (after someone asked about it in #angularjs on freenode).
It probably won't be merged, but it's very similar to ngClass: https://github.com/angular/angular.js/pull/4269
Whether it gets merged or not, the existing ng-attr-* stuff is probably suitable for your needs (as others have mentioned), although it might be a bit clunkier than the more ngClass-style functionality that you're suggesting.
For input field validation you can do:
<input ng-model="discount" type="number" ng-attr-max="{{discountType == '%' ? 100 : undefined}}">
This will apply the attribute max to 100 only if discountType is defined as %
Edit: This answer is related to Angular2+! Sorry, I missed the tag!
Original answer:
As for the very simple case when you only want to apply (or set) an attribute if a certain Input value was set, it's as easy as
<my-element [conditionalAttr]="optionalValue || false">
It's the same as:
<my-element [conditionalAttr]="optionalValue ? optionalValue : false">
(So optionalValue is applied if given otherwise the expression is false and attribute is not applied.)
Example: I had the case, where I let apply a color but also arbitrary styles, where the color attribute didn't work as it was already set (even if the #Input() color wasn't given):
#Component({
selector: "rb-icon",
styleUrls: ["icon.component.scss"],
template: "<span class="ic-{{icon}}" [style.color]="color==color" [ngStyle]="styleObj" ></span>",
})
export class IconComponent {
#Input() icon: string;
#Input() color: string;
#Input() styles: string;
private styleObj: object;
...
}
So, "style.color" was only set, when the color attribute was there, otherwise the color attribute in the "styles" string could be used.
Of course, this could also be achieved with
[style.color]="color"
and
#Input color: (string | boolean) = false;
Was able to get this working:
ng-attr-aria-current="{{::item.isSelected==true ? 'page' : undefined}}"
The nice thing here is that if item.isSelected is false then the attribute simply isn't rendered.
Just in case you need solution for Angular 2 then its simple, use property binding like below, e.g. you want to make input read only conditionally, then add in square braces the attrbute followed by = sign and expression.
<input [readonly]="mode=='VIEW'">

Resources