Dynamically Show/hide directive - angularjs

I am trying to implement some directive, which will be based on the value of one variable in other Service. Here is my code:
if (this.SomeService.variable.condition){
element.show();
} else {
element.hide();
};
However, it is called only once, when the page is bootstraped. How can I make it so that if the variable changes, the element shows/hides? Is there any way to do it without watcher?

You can use ng-show / ng-hide that are angularjs construct used to hide or show a particular piece of HTML.
For example:
<div ng-show="true">HELLO I AM THE FIRST DIV</div>
<div ng-hide="true">HELLO I AM THE SECOND DIV</div>
will return something like
HELLO I AM THE FIRST DIV
Inside ng-show you can put watherver kind of variable so then if your javascript is something like this:
angular.module('mymodule').controller('MyCtrl',[function(){
var self = this;
self.isVisible = true;
}]);
you can use that variable in your code:
<div class="container" ng-controller="MyCtrl as c">
<div ng-show="c.isVisible">HELLO I AM THE FIRST DIV</div>
<div ng-hide="c.isVisible">HELLO I AM THE SECOND DIV</div>
</div>
And the result is the same

Related

AngularJS - One controller on two sibling DOM elements

I'm trying to do a very simple thing. I'm displaying a list of values with Edit links beside them. Clicking the edit link reveals a form that lets you update the value.
(I've simplified the question so the items just have one field "name". My actual use case has more fields, but is canonically equivalent.)
I've run into something that looks like a bug in Angular, but given my limited experience with it, I'm not so sure. Here's how I'm trying to do it:
<div ng-repeat-start="item in items" ng-controller="ItemCtrl as ctrl" ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-repeat-end ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
My controller looks like this:
app.controller('ItemController', function() {
this.isEditing = false;
this.startEditing = function() { this.isEditing = true; }
this.save = function() { this.isEditing = false; }
});
Clicking on Edit link calls the right controller function, and the first div hides. But the second div does not hide.
When I rearrange the code to look like this (essentially wrapping the two divs with a wrapper element), all is well.
<div ng-repeat="item in items" ng-controller="ItemCtrl as ctrl">
<div ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
</div>
Any idea what is technically wrong with the first version? Note that the <input> boxes do get populated with the right values from item.name.
PS: There's a reason why I'm trying to keep the two divs siblings: in my use case, they are actually implemented as two trs which are supposed to appear right below each other in a table.
It's not a bug from angular but it is quite logical.
<div ng-repeat-start="item in items" ng-controller="ItemCtrl as ctrl" ng-hide="ctrl.isEditing">
<span>Name: {{item.name}}.</span>
<a href='#' ng-click='ctrl.startEditing()'>Edit</a>
</div>
<div ng-repeat-end ng-show="ctrl.isEditing">
<input type='text' ng-model='item.name'/>
<a href='#' ng-click='ctrl.save()'>Save</a>
</div>
If you see the above code you have injected controller only to the first div so obviously sibling div doesn't know what is ctrl or ItemCtrl until and unless you do as in you second way.
So if you want to achieve it as sibling, if you are using routing then add the controller attribute in your route path.
So that the controller will be active for that entire template and you can achieve what you want.
Hope it helps.
Thats because controller has its own scope. When you placed controller ONLY on your first div controllers' scope is limited to only this one div. When you wrapped both your divs inside another and place controller on wrapper, controllers' scope now is all that inside this wrapper. So in this case this works fine and this is not the angular bug

ng-switch-when and ng-class compatibility

I was wondering if there were no compatibility issues when ng-switch-when and ng-class are using on the same element like in this sample.
I'm trying to dynamically change the class of this four elements but for some reasons this isn't working on all of them, just on the one who's currently displayed.
Does anyone know what's going on here?
<div>
<div ng-switch="sw" ng-init="sw=1">
<div ng-switch-when="1" ng-class="oneClassOrAnother()"></div>
<div ng-switch-when="2" ng-class="oneClassOrAnother()"></div>
<div ng-switch-when="3" ng-class="oneClassOrAnother()"></div>
<div ng-switch-when="4" ng-class="oneClassOrAnother()"></div>
</div>
<div>
<button ng-click="goTo(1)">1</button>
<button ng-click="goTo(2)">2</button>
<button ng-click="goTo(3)">3</button>
<button ng-click="goTo(4)">4</button>
</div>
</div>
Switch between divs.
$scope.goTo = function(x) {
$scope.sw = x;
}
Return one class or the other one.
$scope.oneClassOrAnother= function() {
if (...) return "class1";
else return "class2";
}
Many thanks.
It doesn't look like you're using the ng-class syntax correctly. Try something like this:
<div ng-class="{class1: oneClassOrAnother()}" ng-switch-when="1">1</div>
Where oneClassOrAnother() returns either true or false and "class1" is the name of the class.
Here's a working example of using ng-class and ng-switch-when together: http://plnkr.co/edit/n86SKEktRcPnBy05o8eZ?p=preview
Angular ngClass docs: https://docs.angularjs.org/api/ng/directive/ngClass
I think its all fine with your code, look at this plunk, I reproduced it and its working. Compare this to your code, maybe you have forgotten about controller?
http://plnkr.co/edit/Lz7L3S?p=preview
Only difference i guess is the fact, that I initiated sw from controller, not from view.
<div ng-switch on="sw">

using ng elements outside of ng-controller

I am inexperienced with angular.
I am using angular to create a series of nested divs (a form) on a webpage. The top div has ng-controller="controllername" as an attribute. Within the nested divs is a div with ng-show="showvar" as an attribute.
It looks like this.
<div class="page">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
</div>
When I perform functions on showvar to make it true, the div appears (and disappears when false) as intended.
I also have a completely separate div 'outside' the the original nest of divs with the ng-controller attribute. As such, there is no ng-controller attribute in this seperate hierarchy BUT I have nested another div inside with the ng-show="showvar" attribute.
Updated HTML structure is as such
<div class="page">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="showvar">More Hidden Stuff</div>
</div>
</div>
When the page loads, both divs with ng-show="showvar" in the separate nests are hidden as ng-hide has been appended by angular. When I perform functions on showvar after the page load to make it true, only the div within the ng-controller div gets shown.
I (think I) understand this is because the ng elements are evaluated at page load (and appended with ng-hide, even outside the controller?) but only the ng elements within the div with the ng-controller attribute are evaluated when functions are performed after page load. Is this correct?
How can I get the other ng-show to be evaluate 'outside' of the ng-controller div?
I was thinking one option is to append ng-controller to the overall 'page' div instead of the nested div. But what other options do I have?
EDIT: I also tried simply adding ng-controller="controllername" to the separate div. I guess angular 'ignores' the duplicate ng-controller div?
The problem your facing is that the showvar resides in your controller's scope, your second usage of the showvar is not within that scope.
What you need to do is make sure the variable is available where needed.
Say you add the variable to the parentController (you don't have one in your example so I'll add one)
<div class="page" ng-controller="parentController">
<div ng-controller="controllername">
<div ng-show="showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="showvar">More Hidden Stuff</div>
</div>
</div>
app.controller('ParentController', function($scope){
$scope.showvar = false;
});
problem with this is when you set showvar to true within your controllername controller it will set it in the innerscope and not the outer. When making sure you have the right scope by accessing it through another object you should be safe.
So try it like this:
<div class="page" ng-controller="parentController">
<div ng-controller="controllername">
<div ng-show="obj.showvar">Hidden Stuff</div>
</div>
<div class="seperate">
<div ng-show="obj.showvar">More Hidden Stuff</div>
</div>
</div>
app.controller('ParentController', function($scope){
$scope.obj = {
showvar: false
}
});
Quick demo
Your issue here is that you ended with 2 "showvar" variables: one within the "controllername" scope and another one on the app scope (as you have a ng-app declaration somewhere in your html parent of the "page" div).
When you load your page, you get the value of "showvar" in the controller scope for the first div, and for the "separate" one, you get the "showvar" variable in the app scope, which doesn't exist, therefore it is resolved to "false" (even though angular declares it for you in your app scope and you can even modify its value later).
When you change the value of "showvar" in the controller scope, it doesn't change the one in the app scope, making the "separate" div stay hidden forever =)

How to show and hide items in dynamic rows in AngularJS?

I'm fairly new to AngularJS and I can't seem to find a way to do this appropriately. I created a custom directive to Apply a function a pass in the row Index. However, I can't seem to think of the way to show items in a row. What would be the best way to do this? I want to show specific and hide a target row via controller.
HTML:
<div class="row" data-index="{{$index}}">
<div>other information</div>
<div class="item hidden" ng-class="{hidden: hidden[{{$index}}]}">
Item
</div>
</div>
My Directive:
scope.$apply(function () {
scope.$parent.showItem(index);
});
Controller:
$scope.teamDrop = function(index) {
$scope.hidden[index] = false;
};
You can use the ng-show and ng-hide directives to hide and show elements.
You can also use the ng-if directive to remove elements from the dom.
For your example I'd change your ng-class to an ng-hide
<div class="row" data-index="{{$index}}">
<div>other information</div>
<div class="item hidden" ng-hide="hidden[$index]">
Item
</div>
</div>
You also don't need to use the {{}} syntax in the ng-class becausue it's already expecting an angular expression, that's for data binding.

Angular ng-class doesn't add dynamic class to element

I'm having trouble grasping that when item.dynamicClass = 'article' why
<div class="type" ng-class="{{ item.dynamicClass }}">
doesn't return a div like:
<div class="type article">
but instead returns:
<div class="type" ng-class="article">
The only way I've been able to get this work is by doing
<div class="type" ng-class="itemClass(item.dynamicClass)">
// Controller
$scope.itemClass = function(type) {
return type;
};
I would like a solution which doesn't involve the controller
I don't think you need the binding braces. What is passed to ng-class is an expression that evaluates to a result, not something to bind (fiddle):
<div class="type" ng-class="item.dynamicClass">

Resources