Why is my ng-hide / show not working with my ng-click? - angularjs

I want to show the elements that contain displayCategory.name with the ng-click above it, but it's not working as expected.
.divider-row
.row-border(ng-hide="showMe")
.row.row-format
.col-xs-12.top-label
Find where you stand
%hr.profile
.row.labelRow
.col-xs-12
%ul
%li(ng-repeat='category in service.categories')
.clear.btn.Category(ng-click='thisCategory(category) ; showMe = true') {{category.name}}
.divider-row
.row-border(ng-show="showMe")
.row.row-format
.col-sm-12.col-md-12.top-label.nopadLeft
What do you think about {{displayCategory.name}}

I dropped your haml into a converter and this is what it spat out (clearly incorrect):
<div class="divider-row">
<div class="row-border">(ng-hide="showMe")
<div class="row row-format">
<div class="col-xs-12 top-label">
Find where you stand
</div>
</div>
<hr class="profile"/>
<div class="row labelRow">
<div class="col-xs-12">
<ul>
<li>(ng-repeat='category in service.categories')
<div class="clear btn Category">(ng-click='thisCategory(category) ; showMe = true') {{category.name}}</div>
</li>
</ul>
</div>
</div>
</div>
<div class="divider-row"></div>
<div class="row-border">(ng-show="showMe")
<div class="row row-format">
<div class="col-sm-12 col-md-12 top-label nopadLeft">
What do you think about {{displayCategory.name}}
</div>
</div>
</div>
</div>
So after some quick googling I found that you should be writing it like this:
.divider-row
.row-border{"ng-hide" => "showMe"}
.row.row-format
.col-xs-12.top-label
Find where you stand...
As that will convert to what you need:
<div class="divider-row">
<div class="row-border" ng-hide="showMe">
<div class="row row-format">
<div class="col-xs-12 top-label">
Find where you stand
Using curly braces instead of round ones for attributes

I cannot run your code to verify, but I think the problem is that the binding property showMe should be replaced with some object like status.showMe.
For example, define $scope.status = { showMe: false}; outside the ng-repeat (in your controller maybe).
Please check a working demonstration: http://jsfiddle.net/jx854d3y/1/
Explanations:
ng-repeat creates a child scope for each item. The child scope prototypical inherits from the parent scope. In your case, the primitive showMe is assigned to the child scope. While you use it outside the ng-repeat, where it tries to get the value from the parent scope, which is undefined. That is why it is not working.
Basic rule is: always use Object, instead of primitive types, for binding.
For more details, please refer to: https://github.com/angular/angular.js/wiki/Understanding-Scopes

Related

angular conditionally show div in nested ng-repeat

<div class="sunti_contain" ng-repeat="sunti in suntis track by $index">
<div class="individual_sunti" ng-click="update_ancestor(sunti)">
<!--needs a unique div#id via angularz-->
<div class="sunti_content" ng-bind="sunti.content"></div>
<div class="sunti_tags" ng-bind="sunti.tags"></div>
<div class="sunti_author" ng-bind="sunti.author"></div>
<div class="sunti_shortid" ng-bind="sunti.short_id"></div>
<div class="sunti_ancestor" ng-bind="sunti.ancestor"></div>
</div>
<div class="sunti_reply_carriage_wrapper">
<div class="sunti_reply_carriage" ng-show="!sunti.descendents.length">
<div class="individual_sunti reply_carriage_sunti" ng-repeat="descendent in sunti.descendents">
<div class="sunti_content" ng-bind="descendent.content"></div>
<div class="sunti_tags" ng-bind="descendent.tags"></div>
<div class="sunti_author" ng-bind="descendent.author"></div>
<div class="sunti_shortid" ng-bind="descendent.short_id"></div>
</div>
</div>
</div>
</div>
I want to only show the div.sunti_reply_carriage if there are any descendents rendered in the ng-repeat. If there are no descendents, I don't want the div sunti_reply_carriage to appear at all. However, the ng-show="!sunti.descendents.length" does not work, presumably because it's just outside/before the ng-repeat that references descendents in sunti.descendents
How can I do this?
ng-show="!sunti.descendents.length"
Above code does not show the following code block if length is greater than zero
Ex: If sunti.descendents.length is 1 then
!1 is false then ng-show="false"
If sunti.descendents.length is 0 then !0 is true then ng-show="true"
So, change the expression to ng-show="sunti.descendents.length"
You can use ng-if as well if you want to completely remove the code block from DOM if the expression evaluates to false.
<div class="sunti_reply_carriage" ng-show="!sunti.descendents.length">
<div class="individual_sunti reply_carriage_sunti" ng-repeat="descendent in sunti.descendents">
<div class="sunti_content" ng-bind="descendent.content"></div>
<div class="sunti_tags" ng-bind="descendent.tags"></div>
<div class="sunti_author" ng-bind="descendent.author"></div>
<div class="sunti_shortid" ng-bind="descendent.short_id"></div>
</div>
</div>
You can use sunti.descendents.length instead of !sunti.descendents.length
If length property returns 0 then it will be hidden because it is falsey value in JavaScript, if it will return some value i.e. a number then it will be shown because it is truthy value in JavaScript.
If you want to show or hide you can use ng-show or ng-hide directives, if you want to completely remove/insert the DOM conditionally then you can use the ng-if directive in this case.
Using the ng-show directive
<div class="sunti_reply_carriage_wrapper">
<div class="sunti_reply_carriage" ng-show="sunti.descendents.length">
<!-- code omitted for brevity -->
</div>
</div>
Using the ng-if directive
<div class="sunti_reply_carriage_wrapper">
<div class="sunti_reply_carriage" ng-if="sunti.descendents.length">
<!-- code omitted for brevity -->
</div>
</div>

ng-click not working on inner div

I have a very simple thing I am trying to do. The ng-click is not working. Any ideas why? Is there a problem with divs that are embedded in another div or am I just too sleepy? That item affected is not included in the code below, but no event is ever registered with the click.
<div ng-switch-when="3" ng-mouseenter="showIcons=true" ng-mouseleave="showIcons=false">
<div ng-if="editPerm" ng-show="showIcons" class="icon_holder" style="width: {{obj.mainwidth}}px;">
<div class="deletebutton"></div>
<div ng-click="equationShow=!equationShow" class="equationspecs"></div>
</div>
<div class="equationBlock">
<div class="eqshow" id="{{obj.itemid}}" ng-show="!obj.showEdit" ng-dblclick="obj.showEdit=!obj.showEdit">
<span mathjax-bind="obj.data.Format_left"></span>=
<span mathjax-bind="obj.data.Format_showequation"></span>=
<span mathjax-bind="obj.data.Format_showsolution"></span>
</div>
If you were able to click on a div with no content in it (sometimes a hard thing to do!), it would simply invert the value of equationShow on the scope.
But that would produce no visible difference. From what I can see in your example, the value of equationShow isn't being used in any way.
Based on your comment, you've probably got a problem with variable scoping.
If, for instance, you did something like this, it'd be more likely to work:
<div ng-init="myVariable = false">
<div ng-if="!myVariable">
<div ng-click="$parent.myVariable = !$parent.myVariable">Show the other div</div>
</div>
<div ng-if="myVariable">
Showing this div
</div>
</div>

Get id of parent element of currently clicked element in AngularJS

How do I get the id of a parent element of currently clicked element in AngularJS?
<div id="d8" class="menutitles ng-scope" ng-repeat="title in list">
<div class="right" ng-click="showsubmenu($event)">+</div>
<div class="left" ng-click="showsubmenu($event)">Unit 9</div>
</div>
How to get the value d8 in showsubmenu($event) function?
Below is what I tried but it doesn't work
$scope.showsubmenu=function(obj)
{
alert(obj.target.parent.attributes.id)
}
It should be parentNode, not just parent:
alert(obj.target.parentNode.id);
Also attributes is redundant as you can access id property directly.
But note, that since you have ngRepeat, it will create invalid markup, since ids are going to be duplicated. You probably want to fix this too, maybe like this or use classes:
<div id="d8{{$index}}" class="menutitles ng-scope" ng-repeat="title in list">
<div class="right" ng-click="showsubmenu()">+</div>
<div class="left" ng-click="showsubmenu()">Unit 9</div>
</div>
<div id="d8" class="menutitles ng-scope" ng-repeat="title in list">
<div class="right" ng-click="showsubmenu()">+</div>
<div class="left" ng-click="showsubmenu()">Unit 9</div>
</div>
It should be enough :D
function showsubmenu($event){
$($event.target).parent();
}
Have a nice day
As an addition to Pedro's answer I'd say that using the jQuery method closest would be preferable.
function showsubmenu($event){
var parent = $($event.target).closest('.yourclass'); // or any selector you prefer
}

Angular.js ng-switch-when not working with dynamic data?

I'm trying to get Angular to generate a CSS slider based on my data. I know that the data is there and am able to generate it for the buttons, but the code won't populate the ng-switch-when for some reason. When I inspect the code, I see this twice (which I know to be correct as I only have two items):
<div ng-repeat="assignment in assignments" ng-animate="'animate'" class="ng-scope">
<!-- ngSwitchWhen: {{assignment.id}} -->
</div>
My actual code:
<div ng-init="thisAssignment='one'">
<div class="btn-group assignments" style="display: block; text-align: center; margin-bottom: 10px">
<span ng-repeat="assignment in assignments">
<button ng-click="thisAssignment = '{{assignment.id}}'" class="btn btn-primary">{{assignment.num}}</button>
</span>
</div>
<div class="well" style="height: 170px;">
<div ng-switch="thisAssignment">
<div class="assignments">
<div ng-repeat="assignment in assignments" ng-animate="'animate'">
<div ng-switch-when='{{assignment.id}}' class="my-switch-animation">
<h2>{{assignment.name}}</h2>
<p>{{assignment.text}}</p>
</div>
</div>
</div>
</div>
</div>
EDIT: This is what I'm trying to emulate, though with dynamic data. http://plnkr.co/edit/WUCyCN68tDR1YzNnCWyS?p=preview
From the docs —
Be aware that the attribute values to match against cannot be expressions. They are
interpreted as literal string values to match against. For example, ng-switch-when="someVal"
will match against the string "someVal" not against the value of the expression
$scope.someVal.
So in other words, ng-switch is for hardcoding conditions in your templates.
You would use it like so:
<div class="assignments">
<div ng-repeat="assignment in assignments" ng-animate="'animate'">
<div ng-switch="assignment.id">
<div ng-switch-when='1' class="my-switch-animation">
<h2>{{assignment.name}}</h2>
<p>{{assignment.text}}</p>
</div>
</div>
</div>
Now this might not fit your use case exactly, so it's possible you'll have to rethink your strategy.
Ng-If is probably what you need — also, you need to be aware of "isolated" scopes. Basically when you use certain directives, like ng-repeat, you create new scopes which are isolated from their parents. So if you change thisAssignmentinside a repeater, you're actually changing the variable inside that specific repeat block and not the whole controller.
Here's a demo of what you're going for.
Notice I assign the selected property to the things array (it's just an object).
Update 12/12/14: Adding a new block of code to clarify the use of ng-switch. The code example above should be considered what not to do.
As I mentioned in my comment. Switch should be thought about exactly like a JavaScript switch. It's for hardcoded switching logic. So for instance in my example posts, there are only going to be a few types of posts. You should know a head of time the types of values you are going to be switching on.
<div ng-repeat="post in posts">
<div ng-switch on="post.type">
<!-- post.type === 'image' -->
<div ng-switch-when="image" class="post post-image">
<img ng-src="{{ post.image }} />
<div ng-bind="post.content"></div>
</div>
<!-- post.type === 'video' -->
<div ng-switch-when="video" class="post post-video">
<video ng-src="{{ post.video }} />
<div ng-bind="post.content"></div>
</div>
<!-- when above doesn't match -->
<div ng-switch-default class="post">
<div ng-bind="post.content"></div>
</div>
</div>
</div>
You could implement this same functionality with ng-if, it's your job to decide what makes sense within your application. In this case the latter is much more succinct, but also more complicated, and you could see it getting much more hairy if the template were any more complex. Basic distinction is ng-switch is declarative, ng-if is imperative.
<div ng-repeat="post in posts">
<div class="post" ng-class="{
'post-image': post.type === 'image',
'post-video': post.type === 'video'">
<video ng-if="post.type === 'video'" ng-src="post.video" />
<img ng-if="post.type === 'image'" ng-src="post.image" />
<div ng-bind="post.content" />
</div>
</div>
Jon is definitely right on. Angular does not support dynamic ngSwitchWhen values. But I wanted it to. I found it actually exceptionally simple to use my own directive in place of ngSwitchWhen. Not only does it support dynamic values but it supports multiple values for each statement (similar to JS switch fall-throughs).
One caveat, it only evaluates the expression once upon compile time, so you must return the correct value immediately. For my purposes this was fine as I was wanting to use constants defined elsewhere in the application. It could probably be modified to dynamically re-evaluate the expressions but that would require more testing with ngSwitch.
I am use angular 1.3.15 but I ran a quick test with angular 1.4.7 and it worked fine there as well.
Plunker Demo
The Code
module.directive('jjSwitchWhen', function() {
// Exact same definition as ngSwitchWhen except for the link fn
return {
// Same as ngSwitchWhen
priority: 1200,
transclude: 'element',
require: '^ngSwitch',
link: function(scope, element, attrs, ctrl, $transclude) {
var caseStms = scope.$eval(attrs.jjSwitchWhen);
caseStms = angular.isArray(caseStms) ? caseStms : [caseStms];
angular.forEach(caseStms, function(caseStm) {
caseStm = '!' + caseStm;
ctrl.cases[caseStm] = ctrl.cases[caseStm] || [];
ctrl.cases[caseStm].push({ transclude: $transclude, element: element });
});
}
};
});
Usage
Controller
$scope.types = {
audio: '.mp3',
video: ['.mp4', '.gif'],
image: ['.jpg', '.png', '.gif'] // Can have multiple matching cases (.gif)
};
Template
<div ng-switch="mediaType">
<div jj-switch-when="types.audio">Audio</div>
<div jj-switch-when="types.video">Video</div>
<div jj-switch-when="types.image">Image</div>
<!-- Even works with ngSwitchWhen -->
<div ng-switch-when=".docx">Document</div>
<div ng-switch-default>Invalid Type</div>
<div>

AngularJS: data-ng-model & data-ng-hide/show

My index.html page is like as follows:
<div id="sidepanel" data-ng-controller="ListCtrl">
<li data-ng-repeat="record in records">
{{record.id}}
<input type="checkbox" data-ng-model="addwidget">
</li>
</div>
<div id="main">
<div data-ng-view></div>
</div>
for this data-ng-view i have another page recordlist.html in that i have following code:
<div data-ng-controller="ListCtrl">
<ul class="design">
<li data-ng-repeat="record in records">
<div data-ng-switch data-on="record.category">
<div data-ng-switch-when="reporting1">
<div id="{{record.id}}" data-ng-show="addwidget">{{record.description}}</div>
</div>
<div data-ng-switch-when="reporting2">
<div id="{{record.id}}" data-ng-hide="addwidget">{{record.description}}</div>
</div>
</li>
</ul>
</div>
My question is i want to show the first div when i check the checkbox & when i uncheck it i want to show the second div.When both of the data-ng-model & data-ng-hide/show are on the same page then it works fine but in my case it present on two different pages.
Is it correct ? How can i implement this. Need Help.Thanks.
The problem is that you are setting addwidget in the first controller, but is trying to use it in the second. Controllers are not singletons.
So, in this situation:
<div id="sidepanel" data-ng-controller="ListCtrl">
...
</div>
<div id="main">
<div data-ng-view>
<div data-ng-controller="ListCtrl">
</div>
</div>
</div>
You got two separated controllers and scopes. And you are setting addwidget in the first trying to read in the second.
You can either bind it to the root scope $root.addwidget or use a service share to the states.
As you have many records, binding directly to root is a problem, as all of them are going to share the same state. So you gonna need an object in the rootScope and bind the option by id $root.addwidget[record.id]. Made a pretty simplified modification here.

Resources