AngularJs Divs won't toggle using <select> - angularjs

I have this in my view:
<div>
<select ng-model="chartType" ng-change="AnalyticsChartTypeChanged(chartType)"
ng-init="chartType='Data grid'">
<option value="Data grid">Data grid</option>
<option value="Histogram">Histogram</option>
</select>
{{chartType}}
<br>showAnalyticsDataGrid == {{showAnalyticsDataGrid}}
<br>showAnalyticsHistogram == {{showAnalyticsHistogram}}
<div ng-show="{{showAnalyticsDataGrid}}">
<p>Data grid goes here</p>
</div>
<div ng-show="{{showAnalyticsHistogram}}">
<p>Histogram goes here</p>
</div>
and the ng-chnage funtion is
$scope.AnalyticsChartTypeChanged = function(chartType)
{
switch (chartType)
{
case 'Data grid': $scope.showAnalyticsDataGrid = true;
$scope.showAnalyticsHistogram = false;
console.log('Show analytics data grid');
break;
case 'Histogram': $scope.showAnalyticsDataGrid = false;
$scope.showAnalyticsHistogram = true;
console.log('Show analytics histogram');
break;
}
}
When I alernately select each of the options, the debug text updates correcrly:
Data grid
showAnalyticsDataGrid == true
showAnalyticsHistogram == false
and
Histogram
showAnalyticsDataGrid == false
showAnalyticsHistogram == true
BUT, it constantly shows the Data grid DIV and never the Historgram DIV.
Obviouly I am making an extermely simple mistake, but I just can't see it :-(

With ng-show, you give it an expression and it evaluates it for you. What you're trying to do here is evaluating the expression by using the double curly braces{{}}, which doesn't make sense. If you simply remove those double curly braces and use the ng-show like this:
ng-show="showAnalyticsDataGrid"
it will work just fine.
Also, remember that those 2 variables aren't being initialized so when the view loads there will be no div shown by default, but you can fix that with an ng-init.
Here's a fiddle. http://jsfiddle.net/5DMjt/5248/

You don't use {{}} interpolation in ng-show. Like many other directives it directly evaluates expressions
Change
<div ng-show="{{showAnalyticsHistogram}}">
To
<div ng-show="showAnalyticsHistogram">

Related

ng-class not working with ng-repeat

I have a situation where I have to add class according to the condition and the ng-class is working according to it even the condition in the ng-class is true.
<ul id="" class="clowd_wall" dnd-list="vm.cardData[columns.id].data"
dnd-drop="vm.callback(item,{targetList: vm.cardData[columns.id].data, targetIndex: index, event: event,item:item,type:'folder',eventType:'sort','root':'folder',current_parent:'folder'})" ng-model="vm.cardData[columns.id].data">
<div class="emptyCol" ng-if="vm.cardData[columns.id].data.length==0">Empty</div>
<li class="dndPlaceholder"></li>
<li class="cont____item" ng-repeat="card in vm.cardData[columns.id].data | orderBy:vm.sort" dnd-draggable="card"
dnd-effect-allowed="move"
dnd-allowed-types="card.allowType"
dnd-moved="vm.cardData[columns.id].data.splice($index, 1)"
dnd-selected="vm.tree.selected = card" ng-class="{emptyCard:card.data.length==0,zoomin:vm.zoomin=='zoomin',emptyCard:!card.data}">
<div class="item" style="height:79%">
<ng-include ng-init = "root = columns.id" src="'app/partials/card.html'"></ng-include>
</div>
</li>
</ul>
ng-class="{'emptyCard': (!card.data || !vm.cardData[columns.id].data.length),'zoomin':(vm.zoomin=='zoomin')}">
Seems like you want to use vm.cardData[columns.id].data.length instead of card.data.length
Your question is not clear as don't know what card.data will contain and ".data" will be present for each iteration
If it is array then this will work "card.data.length" and if there is no "data" key in "card" then ".length" will through error i.e. if card.data itself undefined then it will not have "length" property.
Try to add condition in ng-class one by one then you will be able to figure out which condition is causing problem.
Made some small change
ng-class="{emptyCard: card.data.length==0 || !card.data,zoomin: vm.zoomin=='zoomin'}"
If you have multiple expression, try old fashioned, if it looks best:
Controller:
$scope.getcardClass = function (objCard, strZoomin) {
if (!card.data) {
return 'emptyCard';
} else if (strZoomin =='zoomin') {
return 'zoomin';
} else if (card.data.length == 0) {
return 'emptyCard';
}
};
HTML:
ng-class="vm.getcardClass(card, vm.zoomin)"
NOTE: Replace vm with your controller object.

ngRepeat doesn't refresh rendered value

I'm having an issue with ngRepeat :
I want to display a list of students in two different ways. In the first one they are filtered by group, and in the second they are not filtered.
The whole display being quite complex, I use a ngInclude with a template to display each student. I can switch between view by changing bClasseVue, each switch being followed by a $scope.$apply().
<div ng-if="currentCours.classesOfGroup !== undefined"
ng-show="bClassesVue">
<div ng-repeat="group in currentCours.classesOfGroup">
<br>
<h2>Classe : [[group.name]]</h2>
<div class="list-view">
<div class="twelve cell"
ng-repeat="eleve in group.eleves | orderBy:'lastName'"
ng-include="'liste_eleves.html'">
</div>
</div>
</div>
</div>
<div class="list-view" ng-show="!bClassesVue">
<div class="twelve cell"
ng-repeat="eleve in currentCours.eleves.all"
ng-include="'liste_eleves.html'">
</div>
</div>
My problem happens when my list of students change (currentCours here). Instead of refreshing the ngRepeat, both lists concatenate, but only in the unfiltered view.
I tried adding some $scope.$apply in strategic places (and I synchronize my list for example) but it doesn't help.
EDIT : the function used to refresh currentCours in the controller. It's called when a "cours" is selected inside a menu.
$scope.selectCours = function (cours) {
$scope.bClassesVue = false;
$scope.currentCours = cours;
$scope.currentCours.eleves.sync().then(() => {
if ($scope.currentCours.classe.type_groupe === 1) {
let _elevesByGroup = _.groupBy($scope.currentCours.eleves.all, function (oEleve) {
return oEleve.className;
});
$scope.currentCours.classesOfGroup = [];
for(let group in _elevesByGroup) {
$scope.currentCours.classesOfGroup.push({
name: group,
eleves: _elevesByGroup[group]
});
}
$scope.bClassesVue = true;
}
});
utils.safeApply($scope);
};
Well, I found a workaround, but I still don't know why it didn't work, so if someone could write an explanation, I would be very thankful.
My solution was simply to open and close the template each time I switch between views.

checking multiple condition in ng-if

I need to check 4 conditions in ng-if which are boolean conditions. If any of them is true, I need to display some div.
Is there any simple and better way to do it please?
<div ng-if="ctrl.survivor || ctrl.doctor || ctrl.patient || ctrl.beneficiary">
<div ng-bind-html=" {{ myContent }}">
</div>
</div>
In general, complex logic inside of angular expressions is a code smell:
hard to read
hard to debug
hard to test
In general, I try to avoid boolean logic or anything else that indicates complexity in angular expressions that I write or code review. Instead, I recommend that you extract the logic into a controller method and call the controller method directly. This allows you to also write a nice unit test for it. The final code that I would recommend would look something like this:
<div ng-if="ctrl.isApplicable()">
<div ng-bind-html=" {{ myContent }}"></div>
</div>
In the controller:
class Ctrl {
...
isApplicable() {
return survivor || ctrl.doctor || ctrl.patient || ctrl.beneficiary;
}
...
}

How to make a dynamically added element's ng-show directive apply

First off, I know angularjs is not meant to be used this way but I use it this way anyways :)
Secondly, i just asked this question and got it answered 2 days ago but it doesn't apply for ng-show directive.
Got a list and a set of divs that has ng-show directive each which is hiding em if some value is not equal to list's value. This all hard-coded by the way - again i know i'm not supposed to use angularjs for this
<select ng-model="selected_album">
<option value="1">Album 1</option>
<option value="2">Album 2</option>
....
<div ng-show="selected_album == 1">.....
<div ng-show="selected_album == 1">.....
<div ng-show="selected_album == 1">.....
<div ng-show="selected_album == 2">.....
.....
Got a js function that uploads images and then adds to DOM inside in its own div with specific ng-show="selected_album == CURRENT_SELECTED_INDEX" directive like
$scope.upload = function(files){
.....
// after upload progress below is the part that creates and adds the div
var div_new = document.createElement("div");
div_new.className = "overlay_thumb";
div_new.setAttribute("ng-show", ("selected_album == " + selected_index));
div_new.innerHTML = 'stuff';
div_some.parentNode.insertBefore(div_new, div_some.nextSibling);
$compile(div_new)($scope);
// there is no fail until here. div is being added to DOM just fine
// but angularjs is adding ng-shide to it directly i dont know why so
// i wrote this to remove ng-hide from it
$timeout(function(){ div_new.classList.remove("ng-hide"); },200);
....
}
Even ng-click directives of the elements inside that new div are working but not ng-show for the div. How to make it work?

How to update ng-class based on ng-change?

I have an ng-repeat that creates several widgets, each with it's own select dropdown.
<div ng-repeat="item in widget.items" class="col-md-6">
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="widget.getButtonClass(item.tag, item.id)">
<option value="companies"
ng-selected="{{item.tag == 'companies'}}"
changed="companies">companies</option>
<option value="news"
ng-selected="{{item.tag == 'news'}}"
changed="news">news</option>
<option value="people"
ng-selected="{{item.tag == 'people'}}"
changed="people">people</option>
</select>
</div>
As the view is loaded, the ng-class="widget.getButtonClass(item.tag, item.id)" calls a function to check if 2 values are met, then sets ng-class to either btn-success or btn-default.
// This checks the view after load to change the class on each widget select
var vm = this;
vm.getButtonClass = function(tag, id) {
console.log('in getButtonClass');
if (tag && id) {
return 'btn-success';
} else {
return 'btn-default';
}
};
Next if the user now updates a select within any widget, ng-change will update to the correct value.
However I need to somehow re-run the ng-class check or rather just go ahead and add btn-success to the select without having to refresh the page.
How would you go about accomplishing this?
Is there a way to do something like this?
ng-class="{ functionToUpdateAll | boolean based on ng-change }"
Is there any specific reason that you need to call the function? Why dont you bind directly to those variables?
ng-class="'btn-success':item.tag && item.id, 'btn-default': !(item.tag && item.id)"
In that way you take advantage of mutual binding i.e. whenever the item.tag or item.id are changed, the class will be evaluated accordingly.
I suggest that instead of calling the function in ng-class, just assign it to a variable:
<select ng-model="item.chosenTag"
ng-change="widget.updateTag(item)"
ng-class="mySelectClass">
And in your updateTag function in the controller update that variable:
vm.updateTag = function(item) {
if (item.tag && item.id) {
vm.mySelectClass = 'btn-success';
} else {
vm.mySelectClass = 'btn-default';
}
};

Resources