ng-class to be only added if <a> exists after given element - javascript

I have a list of items that are grouped by labels, and am using filter to search through this list. The issue is that labels for lists are still showing in the search, however lists themselves are empty, hence I need to hide appropriate label. To do so I can check if anchor tag exists after my label with class .item, if it doesn't then I want to add .hidden class to the label.
I tried following, but as I am new to angular it obviously didn't work:
<div class="label" ng-class="next(a).length <= 0 ? 'hidden'">
My Label
</div>
And this is how whole group/section looks if there are items in the list:
<div class="list search-list">
<div class="label" ng-class="next(a).length <= 0 ? 'hidden'">
My Label
</div>
<a class="item> .. </a>
<!-- More a tags here -->
<div class="label" ng-class="next(a).length <= 0 ? 'hidden'">
My Label 2
</div>
<a class="item> .. </a>
<!-- More a tags here -->
</div>
I checked with inspector, relevant a tags are indeed being removed if they don't match search.
UPDATE:
added false case to ng-class, but still no luck
<div class="label" ng-class="next(a).length <= 0 ? 'hidden' : 'shown'">
My Label
</div>
UPDATE2: Full structure
<ion-view view-title="Search">
<ion-content ng-controller="SearchCtrl">
<div class="list search-bar">
<label class="item item-input">
<i class="icon ion-ios-search-strong placeholder-icon"></i>
<input type="text" placeholder="What are you looking for?" ng-model="searchFilter">
</label>
</div>
<div class="list search-list">
<!-- Group 1 -->
<div class="item item-divider" ng-class="angular.next('a').length <= 0 ? 'hidden' : 'shown'">
My Title
</div>
<a
class="item item-avatar"
href="#/app/{{item.link}}"
ng-repeat="item in items | filter:searchFilter">
<img src="img/item.png">
<h2>{{item.title}}</h2>
<p>Description</p>
</a>
<!-- Group 2 -->
<div class="item item-divider" ng-class="angular.next('a').length <= 0 ? 'hidden' : 'shown'">
My Title 2
</div>
<a
class="item item-avatar"
href="#/app/{{item2.link}}"
ng-repeat="item2 in items2 | filter:searchFilter">
<img src="img/item2.png">
<h2>{{item.title}}</h2>
<p>Description 2</p>
</a>
</div>
</ion-content>
</ion-view>

In case you want to follow the original approach of checking if there is <a/> element after your <div> you can write a custom directive. Here is one that checks for that condition:
.directive('conditionalDisplay', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
if (element.next('a.item').length == 0)
element.css('display', 'none');
}
}
});
And here is how I used it:
<div class="list search-list">
<div conditional-display class="label">
My Label (Not Displayed, because there is no next a element)
</div>
<!--<a class="item"> .. </a>-->
<!-- More a tags here -->
<div conditional-display class="label">
My Label 2 (Displayed)
</div>
<a class="item"></a>
<!-- More a tags here -->
</div>
Here is a working plunker: http://plnkr.co/edit/ytCVxuBnbZAbX0faiQ4m?p=preview
One important thing: Make sure you include jquery for the next() selector to work. JQLite does not support next() with selectors.
Personally, I like #pgreen2 's approach. It more like angular way of doing stuff.

As described by ng-init, you could store the results of the filter and then reference like below:
<!-- Group 1 -->
<div ng-init="filteredItems = (items | filter:searchFilter)" ng-if="filteredItems">
<div class="item item-divider">
My Title
</div>
<a class="item item-avatar" href="#/app/{{item.link}}" ng-repeat="item in filteredItems">
<img src="img/item.png">
<h2>{{item.title}}</h2>
<p>Description</p>
</a>
</div>
I wrapped the whole group in a div that has ng-init which creates a variable called filteredItems that us it two other places. The first is to conditinally render the entire div using ng-if. I believe this will resolve your actual question. Secondly, I use filteredItems in the ng-repeat for the anchor tags.

Related

Plugin not applying changes on ngFor directed div Angular 5.2

I've been searching for the solution for a few days but unable to find one that works. The issue is that this div which has a class ish-container-inner, is linked to a js plugin which works only with this code below:
<div class="ish-container-inner ish-product">
<div class="ish-main-content ish-pflo-gal ish-scroll-anim ish-2col ish-square ish-content-parallax">
<div class="ish-item">
<div class="ish-item-container">
<div class="ish-caption-container">
<div class="ish-caption">
<span class="ish-h4 ish-txt-color9">Special Effects</span> <span class="ish-separator">/</span> <span>Ink</span></div>
</div>
<div class="ish-img">
<img src="assets/img/bniinks-003.jpg" alt="Project">
</div>
</div>
</div>
</div>
</div>
But as soon as I'll put *ngFor like below, it won't work. Even with ngIf present:
<div class="ish-container-inner ish-product" *ngIf="products">
<div class="ish-main-content ish-pflo-gal ish-scroll-anim ish-2col ish-square ish-content-parallax">
<div class="ish-item" *ngFor="let product of products">
<div class="ish-item-container">
<div class="ish-caption-container">
<div class="ish-caption">
<span class="ish-h4 ish-txt-color7">{{ product.name }}</span> <span class="ish-separator">/</span> <span>Ink</span>
</div>
</div>
<div class="ish-img">
<a href="product-detail.html" class="ish-img-scale" [style.background]="'url('+product.thumbnail+')'">
<img src="{{product.thumbnail}}" alt="Project"></a>
</div>
</div>
</div>
</div>
</div>
I have valid data at this point in products but the plugin is not working for these div elements. I don't know why. Without the ngFor directive. Div is assigned some stylings automatically which are changed by the plugin on scroll i.e.
<div class="ish-main-content ish-pflo-gal ish-scroll-anim ish-2col ish-square ish-content-parallax" style="position: relative; height: 629px; margin-top: -99.5455px;" data-initial-top="0">
But if I put ngIf or ngFor directive. It doesn't work anymore and these stylings are not assigned automatically. Awaiting response :)

Selecting only one child element in AngularJS with jquery

So, I had a working function in jQuery but then I decided to use Angular for my application. Just can't find the way so it adds the CSS to only one child element.
Jquery code that was working
$('.list-div').on('mouseenter', function(){
$(this).find('.client-jar').css('opacity','1');
}).on('mouseleave', function() {
$(this).find('.client-jar').css('opacity','0');
});
Current html
<ul>
<li ng-repeat="one in ones | orderBy:'-date'">
<div class="list-div">
<div class="row jar-div first-jar-div" ng-mouseover="showButton()" ng-mouseleave="hideButton()">
<div class="col-xs-7 description-div">
<p class="version">{{ one.version }}</p>
<p class="date">{{ one.date }}</p>
</div>
<div class="col-xs-5 buttons-div">
<div class="list-button client-jar">
<a class="list-link" data-toggle="modal" data-target="#myModal">create server</a>
</div>
<div class="list-button server-jar">
<a class="list-link">Server jar</a>
</div>
</div>
</div>
</div>
</li>
</ul>
And Current Angular JS
$scope.showButton = function(){
angular.element('.list-div').find('.client-jar').css('opacity','1');
};
$scope.hideButton = function(){
angular.element('.list-div').find('.client-jar').css('opacity','0');
};
I would use:
https://docs.angularjs.org/api/ng/directive/ngMouseenter
<button ng-mouseenter="hoverState = true">mouse in mouse out</button>
Then use with:
https://docs.angularjs.org/api/ng/directive/ngMouseleave
<button ng-mouseenter="hoverState = true" ng-mouseleave="hoverState = false">mouse in mouse out</button>
At this point you have a hover over and off flag. You can now pick this flag up with ng-class to set and unset a CSS class which contains your opacity stuff, and any future CSS animations etc etc:
https://docs.angularjs.org/api/ng/directive/ngClass
<button ng-mouseenter="hoverState = true" ng-mouseleave="hoverState = false" ng-class="{'opacity-class':hoverState}">mouse in mouse out</button>
No jQuery required, AngularJS is just a totally different way of going about things.
<style>
.opacity-class .client-jar{
opacity:0;
}
</style>
<ul>
<li ng-repeat="one in ones | orderBy:'-date'">
<div class="list-div">
<div class="row jar-div first-jar-div" ng-mouseenter="hoverState = true" ng-mouseleave="hoverState = false" ng-class="{'opacity-class':hoverState}">
<div class="col-xs-7 description-div">
<p class="version">{{ one.version }}</p>
<p class="date">{{ one.date }}</p>
</div>
<div class="col-xs-5 buttons-div">
<div class="list-button client-jar">
<a class="list-link" data-toggle="modal" data-target="#myModal">create server</a>
</div>
<div class="list-button server-jar">
<a class="list-link">Server jar</a>
</div>
</div>
</div>
</div>
</li>
</ul>
angular.module('App').directive('listFade', function() {
return function(scope, element) {
element.bind('mouseover', function(children) {
// YOUR ANIMATION CODE HERE
});
element.bind('mouseout', function(children) {
// YOUR ANIMATION OUT CODE HERE
});
}
})
then just add the directive to your ng-repeat markup, list-fade=""
you don't need children but its a easy way to call the children of each element. This should help you out. Then get rid of that ng-mouseover showButton();
Updating your code to use inline CSS, would be like this.
var element = document.querySelector('.list-div .client-jar');
$scope.showButton = function(){
angular.element(element).css('opacity','1');
};
$scope.hideButton = function(){
angular.element(element).css('opacity','0');
};
As in AngularJS .element documentation, it's said that you need to pass a element.
You can also use ng-class, creating a class for opacity:
<div class="client-jar" ng-class="{class: expression}"></div>
https://docs.angularjs.org/api/ng/directive/ngClass
Or use ng-show and ng-hide for display control:
<div class="client-jar" ng-show="expression"></div>
https://docs.angularjs.org/api/ng/directive/ngShow
You could even use ng-style for inline css:
<div class="client-jar" ng-style="{'opacity': '1'}"></div>
https://docs.angularjs.org/api/ng/directive/ngStyle

Angularjs ng-repeat and child elements

I'm attempting to insert a <br/> every nth element to achieve something like this (using ng-repeat and ng-if="!($index % 2)"):
<div class="container">
<div>
<span>1</span>
<span>2</span>
<br/>
<span>3</span>
</div>
</div>
I thought I could mimic how i've used ng-repeat in the past for <ul/> elements, as so:
<div class="container">
<ul ng-repeat="item in list">
<li>{{item}}</li>
</ul>
</div>
which produces a list such as this:
<div class="container">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>
Yet when I attempt to do something like this:
<div class="container">
<div ng-repeat="item in list">
<span>{{item}}</span>
</div>
</div>
I get this differing result from the <ul/> usecase:
<div class="container">
<div>
<span>1</span>
</div>
<div>
<span>2</span>
</div>
<div>
<span>3</span>
</div>
</div>
The question is two-fold:
Why does the ng-repeat directive on a <ul/> behave differently
How can I have multiple span elements then a break without wrapping each span in a div?
https://docs.angularjs.org/api/ng/directive/ngRepeat
The ngRepeat directive instantiates a template once per item from a
collection. Each template instance gets its own scope, where the given
loop variable is set to the current collection item, and $index is set
to the item index or key.
In your loop, your 'item' has following local variables: $index, $first, $middle, $last, $even, $odd. Each except $index returns a boolean value that tells you if the item is, for example, $odd. Also take a look at the directive ngClassEven.
ng-repeat acts equal to any tag, maybe the presatantion of ul creates confusion,
look next example:
http://plnkr.co/edit/ig766DNNlQXihNS5ZGdY?p=preview
im separated:
<ul class="example-animate-container">
<li class="animate-repeat" ng-repeat="friend in friends">
and
<legeng>ul - ng repeat</legeng>
<ul class="example-animate-container" ng-repeat="friend in friends">
Try this.
<div ng-repeat="num in [1,2,3,4,5,6]">
<div>{{num}}</div>
<div ng-if="$index%2">whatever you want</div>
</div>
Result looks something like this.
1
2
whatever you want
3
4
whatever you want
5
6
whatever you want
Update:
If you want to insert a <br> every nth <span> then you can change your HTML to the following:
<div id="container">
<span ng-repeat="item in list">{{item}}
<br ng-if="$index % 2">
</span>
</div>
Tested in Firefox,Chrome,and Internet Explorer the results look like this:
12
34
56
All you have to do is remove the surrounding div elements and then change your html to the following(live preview: http://codepen.io/larryjoelane/pen/qbJXJm). The ng-repeat directive duplicates the number of child elements that are contained within the parent element. The <li> elements in your example do not contain any child elements. In other words <li> elements are child elements of the <ul> element by default. However <span> elements are not child elements of <div> elements by default. You will see similar behavior when you use ng-repeat for other elements like the <table> element and its <tr> and <td> tags.
HTML:
<div ng-app="app" ng-controller="spans">
<div id="container">
<span ng-repeat="item in list">{{item}}
</span>
</div>
</div>
Angular/JavaScript:
angular.module("app", []).controller("spans", ["$scope", function($scope) {
$scope.list = [1, 2, 3, 4, 5, 6];
}]);
And if you want each span to have a line break then apply the following CSS:
#container span {
display: block;
}

JQuery Parent-Child Selection

I am new to jQuery and am trying to write a script that will run through a menu list and display the correct background image based on the menu item. The menu list is going to be randomly populated so a script is necessary to load the correct image.
The problem is that the attribute where I am able to see which item the menu belongs to is not on the list item itself but on a div contained inside the list item. My question is is it possible to select a child element of the already selected element ?
E.g (the menuli a segment)
$(document).ready( function() {
$(menuli).each( function(index) {
$itemnumber = $(menuli a).attr("href");
switch($itemnumber) {
case 1:
$(this).css("background-image", "image01.jpg");
break;
}
});
});
This is more or less the script I am trying to get, where each list item is iterated through and depending on the href of the link inside the list item a background image is set to that list item.
EDIT
Here is my html:
<div id="divMenuSportGSXSports">
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=468&Antepost=0&)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl00_lnkSport" href="/Sport/Groups.aspx?IDSport=468&Antepost=0">
<span title="SOCCER">SOCCER</span>
</a>
</div>
</div>
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=520&Antepost=0&)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl01_lnkSport" href="/Sport/Groups.aspx?IDSport=520&Antepost=0">
<span title="BASEBALL">BASEBALL</span>
</a>
</div>
</div>
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=544&Antepost=0&)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl02_lnkSport" href="/Sport/Groups.aspx?IDSport=544&Antepost=0">
<span title="CRICKET">CRICKET</span>
</a>
</div>
</div>
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=525&Antepost=0&Tema=Supabets)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl03_lnkSport" href="/Sport/Groups.aspx?IDSport=525&Antepost=0">
<span title="BASKETBALL">BASKETBALL</span>
</a>
</div>
</div>
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=534&Antepost=0&)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl04_lnkSport" href="/Sport/Groups.aspx?IDSport=534&Antepost=0">
<span title="ICE HOCKEY">ICE HOCKEY</span>
</a>
</div>
</div>
<div class="VociMenuSportG">
<div class="ImgSport" style="background-image:url(../ImgSport.ashx?IDBook=53&IDSport=523&Antepost=0&)">
<img src="buttons_void.png">
</div>
<div class="NomeSport">
<a id="h_w_PC_cSport_repSport_ctl05_lnkSport" href="/Sport/Groups.aspx?IDSport=523&Antepost=0">
<span title="TENNIS">TENNIS</span>
</a>
</div>
</div>
</div>
Yes you can, use find
var parentElement = $('#someElement');
var childElement = parentElement.find('.child'); //where .child should be your child selector
Where as example code is not clear, I just gave answer to your question.
try to change this:
$(this).css("background-image", "image01.jpg");
to this:
$(this).children("div").css("background-image", "image01.jpg");
If you want to target the direct child of the element, better to use children() than find()
Please refer to this: What is fastest children() or find() in jQuery?

Write a jQuery selector to filter the child divs having no subclasses

Consider the following HTML
<div class="container">
<div class="item medium type"> value1 </div>
<div class="item"> value2 </div>
<div class="item large"> value3 </div>
<div class="item small"> value4 </div>
<div class="item"> value5 </div>
<div class="item"> value6 </div>
<div class="item"> value7 </div>
<div class="item medium"> value8 </div>
<div class="item"> value9 </div>
</div>
Is there a straightforward way to write a jQuery selector to get all the children of the container div which does not possess any subclasses ?
For example, I need to write a selector ($('myselector').each()) and get only the item divs with values value2,value5,value6,value7,value9 (as these divs don't have any subclasses).
May be I am missing the obvious. But I did a quick search to get little information on this.
You can use this selector:
$('.container [class=item]')
It get every child with a class attribute exactly equal to item (so there is no other class).
But it's not really scalable, what if you need to add another class that don't exclude the element?
Maybe you should consider adding a class to other elements like:
<div class="container">
<div class="item sub medium type"> value1 </div>
<div class="item"> value2 </div>
<div class="item sub large"> value3 </div>
<div class="item sub small"> value4 </div>
<div class="item"> value5 </div>
<div class="item"> value6 </div>
<div class="item"> value7 </div>
<div class="item sub medium"> value8 </div>
<div class="item"> value9 </div>
</div>
And then use :not in your selector:
$('.container .item:not(.sub)')
You can use $("div[class$='item']")
Also you may take a look at http://api.jquery.com/category/selectors/
If you use the attribute selector like this:
$('.container [class=item]')
then it will only match an element that is exactly like this:
<div class="item">value1</div>
and not this (notice the whitespace around the class name "item"):
<div class=" item ">value1</div>
It is not safe to assume that there will never be whitespace in the class attribute. It's possible that whitespace gets inserted or left behind as the result of some jQuery DOM manipulation. A solution to this would be to trim the class attribute before selecting all elements with only the class "item".
$('.container')
.children() // select all the elements contained within .container
.each(function(){
// strip whitespace from class attribute
$(this).attr('class',$.trim($(this).attr('class')));
});
// fade out all elements within .container that ONLY have the class
// "item" and nothing else
$('.container [class="item"]').fadeOut();
try not
$('.container .item').not('.medium , .large,.small,.type')
or the attribute selector
$('.container [class=item]').each(function(){
//do your stuff
});

Categories

Resources