Toggling or accordian effect using Angular - javascript

First of all i am new to angular, so i can't able to figure out how to achieve the below scenario.
On click I can able to show/Hide the relevant div for each row. But if the tooltip is open (let's say on 1st row it is opened) in one row and i am clicking on another row (let's say i am clicking on 3rd row ) then the open tooltip (from 1st row ) is not hiding. Please help me on this.
Below is my code,
<div ng-repeat="breakdown in CallFullbreakdown" class="list-items-row">
<div class="mob-number"><a data-ng-click="toggleDetails = !toggleDetails">{{breakdown.number}}</a></div>
<div class="call-date"><a data-ng-click="toggleDetails = !toggleDetails">{{breakdown.dateandtime}}</a></div>
<div class="call-cost text-align-right"><a data-ng-click="toggleDetails = !toggleDetails">£{{breakdown.cost}} <span class="chevron-style icon-up-chevron"></span></a></div>
<!-- Start Call Breakdown Tooltip -->
<div class="row position-relative call-breakdown" data-ng-show="toggleDetails">
<span class="sprite arrow grey-arrow call-breakdown-arrow"></span>
<div class="mob-number">
<span class="bolder">Call type</span>
<span>{{breakdown.callType}}</span>
</div>
<div class="call-date">
<span class="bolder">Destination</span>
<span>{{breakdown.destination}}</span>
</div>
<div class="call-cost text-align-right">
<span class="bolder">Duration</span>
<span>{{breakdown.duration}}</span>
</div>
</div>
<!-- End Call Breakdown Tooltip -->
</div>

Just switching one toggleDetails variable for all cannot close one while opening the other. Instead, create a reference to the breakdown curently opened in your controller.
Then, make toggleDetails a function taking the breakdown to toggle as an argument. That function can then control which breakdown is currently showing ist Details.
In your BreakdownController:
(...)
var activeBreakdown;
$scope.toggleDetails = function(breakdown) {
if (breakdown === activeBreakdown) {
// Breakdown is defined, so activeBreakdown must be as well
activeBreakdown.showDetails = !activeBreakdown.showDetails;
} else {
if (activeBreakdown) {
// Make sure the currently active breakdown is closed
activeBreakdown.showDetails = false;
}
// If a new breakdown is selected, it needs to be opened
breakdown.showDetails = true;
// And put on activeBreakdown so it can be closed on the next toggle
activeBreakdown = breakdown;
}
};
(...)
html:
<div ng-repeat="breakdown in callFullBreakdown" class="list-items-row">
<!-- Breakdown row stuff here... -->
<!-- Start Call Breakdown Tooltip -->
<div class="row position-relative call-breakdown" style="background-color: #a0a0a0" ng-show="breakdown.showDetails">
<!-- Details/tooltip here -->
</div>
<!-- End Call Breakdown Tooltip -->
<hr />
</div>
See this Plunk
Also, to save on ng-clicks (and therefore also reduce the amount of potential error when changing something), see if you can wrap the row part (number, dateandtime, cost) in another element and put the ng-click there.

This is the first thing that bumped into my eyes:
data-ng-show="toggleDetails" data-ng-hide="!toggleDetails"
ng-show serves the purpose of showing AND hidding and element, depending on the boolean value of the variable assigned to it.
Using both on the same element is just a mess.
Also, you've spread the ng-show/hide all over the place. Couldn't it be done at the container level?
Ideally, you should give us a working sample on jsfiddle and we'll fix it from there.

Related

How to show and hide the data when the particular condition is true in angular

In my angular application I have created the dashboard page In that created the map and right side placed the data to display something about the map (i.e created the circle in the map of 5km radius if the marker inside the circle show the details of the marker).
I have written the if condition for the marker comes inside the circle it should be turned to red otherwise blue.
And in Html I have created the bootstrap tabs with id (drones).
component.ts
inQuadrant(quadrant) {
var inPolygon = this.isMarkerInsidePolygon(this.droneMarker, quadrant);
if (inPolygon) {
quadrant.setStyle({color: 'red'});
const isRed=true;
} else {
quadrant.setStyle({color: '#3388ff'});
}
}
component.html
<div class="tab-pane fade " id="Drones" >
<ul class="list-group card" id="dd">
<li class="list-group-item" *ngFor="let x of datas">
<div class="row no-gutters">
<div class="col-sm-3" >
<div class="card-body">
<img src="{{drone01.iconref}}" width="90" height="90">
</div>
</div>
</div>
</li>
</ul>
</div>
So my requirement is how to show and hide the data when the drone comes in side(the data of id=drones should have to be shown) and outside (the data of id=drones have to be disappear)
Can anyone help me regarding this.I have tried multiple ways.
I'm afraid you're approaching this in a very non-angular way - it's a bit difficult to give a good answer with the limited amount of code you're providing, but here goes:
If you wish to hide things, you can either:
Use *ngIf to display or not display the item, or bind to the CSS visibility-property, eg.: [visibility]=isHidden ? 'hidden' : 'visible'.
But I might be misunderstanding your question?
Manipulating HTMLElements (quadrant.setStyle) is an anti-pattern in angular, you should instead use property bindings.

Dynamically creating jQuery UI sliders: I want to set unique ids for both slider handles to give them custom text

I'm dynamically creating jQuery UI sliders, using the following code in a forEach loop:
// Sets an id for the slider handles, gives them a custom class (makes them appear as circles, centers them)
$("#slideRange" + i).find(".ui-slider-handle").attr("id","slideHandle" + i).addClass("customSliderHandle");
// These two lines set the times below the slider handles.
$("#timeSlider" + i).find(".slideStartLabel").text(startTime);
$("#timeSlider" + i).find(".slideEndLabel").text(endTime);
This successfully makes the following slider, with variable times, for every iteration:
What I'd like to do, instead of showing the times below the circular handles, is have the times appear in the middle of the handles. The end result would look like this (photoshopped):
The times will then update, according to the slider values, within the "slide" event callback.
My question is: how do I assign unique id's to the two slider handles, so that I can then set their text independently in the "slide" callback? The code I wrote above gives both handles the same id. Using this id to set text to a handle will only apply to the first handle, leaving me no way to change the text of the second. Using find(), get(), or just $(".ui-slider-handle") are all ways of getting an array of the slider handles, but when I try attr("id","uniqueId") on one of the elements of that array, I get "(...).method(...) is not a method".
Or is assigning unique id's the wrong approach, here? Is there a jQuery or vanilla Js way of setting attributes of one element at a time, when searching by class and getting potentially multiple results?
Also, for context: I'm using find() because I'm using clone() on a markup shell, then appending it to a central div. Here's the shell:
<!-- This hidden div will be cloned, customized, and appended onto .modal-body -->
<div id="timeslotShell" class="timeslot row" style="display:none">
<div class="container-fluid slotContents" id="slotContents">
<span class="col-md-4"> Listing <div class="slotNumber listNum">*Listing No.*</div>: From <div class="slotNumber startNumber slotStartShell"> *Start Time* </div> until
<div class="slotNumber endNumber slotEndShell"> *End Time* </div> </span>
<div class="col-md-8">
<button type="button" class="btn btn-md btn-info slotButton">
Choose A Time From Within These Hours
</button>
</div>
<div id="timeSliderShell" class="collapse timeSlider">
<br><br>
<div id="slider-range" class="slideRange row"></div>
<div id="slideLabels" class="slideLabels slideRange row">
<div class="slideStartLabel"></div><div class="slideEndLabel"></div>
</div>
</div>
</div>
<br><br>
</div>
Cool -- as luck with have it, I found the answer shortly after posting this. Check this post if you're dealing with a similar issue:
Slider Value Display with jQuery UI - 2 handles
All that's needed, in the .find() calls, is
.find(".ui-slider-handle:first").text(value1);
for the first handle and then
.find(".ui-slider-handle:last").text(value2);
for the second.

Angular ng-repeat, Jquery fail

So I am using ng-repeat to repeat some divs which show images out of my JSON file. What I want to do is that when I click on that image (whether its desktop or mobile) the image will scale. Now my problem is that when I want to create a click event on my image tag (which is inside that div that holds the ng-repeat), he doesn't do anything. He cant see the click.
I red something on the internet about issues with jquery and angular, but for me as a beginner its hard to understand what I have to do to make it work how I pleased. I just want to be able to put a jquery function on a image tag inside the ng-repeated divs, so I can manipulate the css from there.
I have a piece of the code posted below here, maybe I have to add something to my controller? I dont know, I am clueless at the moment. :-)
<section class="words">
<div class="colored-sidebar"></div>
<!-- content -->
<div class="previous-button"></div>
<div class="word-container" ng-controller="imageController as imageCtrl">
<h1><span>noun</span>words</h1>
<div class="category-body">
<p><span>noun</span>travel</p><hr>
<div class="category-section" ng-repeat="icon in imageCtrl.imageList.travel">
<!-- <div class="category-image" ng-include="icon.src"></div> -->
<div class="category-image">
<img src="{{icon.src}}" />
</div>
</div>
</div>
</section>
The angular file
(function() {
app.controller('imageController', function(){
this.imageList = imageJson;
});
var imageJson = {
//ALOT OF JSON DATA HERE//
};
})();
I hope this piece of code would be enough to help me :-)
Any tips are welcome, I love to learn this language better and also understand it better.
Thanks!
jQuery is not suitable here, because by the time you run your jQuery code inside jQuery.ready(), the elements in "category-image" class are not created yet.
For solution of your problem you can use two methods:
1) Use the "ng-click", as proposed before. You can also pass "$index" to function inside ng-click. This way you will know index of icon in imageList.travel that was clicked. But this way you will have no information about dom element.
2) Create a directive. The main difference between directives and controllers is that directive have information about dom object. You can treat element as typical jQuery object
JS:
app.directive('imageClick', [function () {
return {
link: function (scope, element, attr) {
element.on("click", function(e){
//do some stuff here
})
}
}
}]);
HTML
<section class="words">
<div class="colored-sidebar"></div>
<!-- content -->
<div class="previous-button"></div>
<div class="word-container" ng-controller="imageController as imageCtrl">
<h1><span>noun</span>words</h1>
<div class="category-body">
<p><span>noun</span>travel</p><hr>
<div class="category-section" ng-repeat="icon in imageCtrl.imageList.travel">
<!-- <div class="category-image" ng-include="icon.src"></div> -->
<div class="category-image">
<img image-click src="{{icon.src}}" />
</div>
</div>
</div>
</section>

Store multiple CSS classes in an array

I'm still pretty new to JQuery and JavaScript as a whole, so bear with me. I tried searching the web for an answer to my question and experimented a little bit, but I'm coming up dry. Anyway, is there a way to store multiple CSS classes in an array with JavaScript?
I'm writing some simple JQuery for a friend's portfolio website such as this:
$('.item.two').click(function(){
$('.content.item, .current.item').show();
$('.content.item, .content.item, .content.item, .current.item, .current.item, .current.item').hide();
$('.item.one, .item.three, .item.four').fadeTo(0, 0.5);
$('.item.two').fadeTo(0, 1.0);
});
All this is doing is hiding certain elements and only showing them when their corresponding icon is clicked on. This is also turning the opacity from 50% off the main class to 100% when clicked on.
There's nothing wrong with the code itself, it serves its intended purpose. But is there a way to clean this code up a bit by just holding those classes into a reusable array? I feel like it should be possible, but I'm not sure how.
Thanks!
EDIT: Sorry, I wasn't clear that I'm actually using 4 different classes to hide or show. So instead of the previous bit it's actually
$('.item.two').click(function(){
// this is the content i want to show on click
$('.content.itemTwo').show();
// this is the content that i want to hide/remain hiding on click
$('.content.itemOne, .content.itemThree, .content.itemFour').hide();
// these are icons representing the content
$('.item.one, .item.three, .item.four').fadeTo(0, 0.5);
$('.item.two').fadeTo(0, 1.0);
});
Also, here is my HTML some of you are requesting. Like I said, what I'm trying to make happen, happens. I just feel like there's a better way of making it happen.
<!-- these are icons representing the written content-->
<div class="item one">
<div class="fs1" aria-hidden="true" data-icon=""></div>
</div>
<div class="item two">
<div class="fs1" aria-hidden="true" data-icon=""></div>
</div>
<div class="item three">
<div class="fs1" aria-hidden="true" data-icon=""></div>
</div>
<div class="item four">
<div class="fs1" aria-hidden="true" data-icon=""></div>
</div>
<!-- this is the written content to be shown upon clicking corresponding icon -->
<div class="content itemOne">
<h3>itemOne</h3>
<p>....</p>
</div>
<div class="content itemTwo">
<h3>itemTwo</h3>
<p>...</p>
<div class="content itemThree">
<h3>itemThree</h3>
<p>...</p>
</div>
<div class="content itemFour">
<h3>itemFour</h3>
<p>....</p>
</div>
Looking at it now, I probably don't need the extra selectors on the .content or .item.
If I correctly understood , you are trying to change the element that is clicked.
$('.item.two').click(function(){
// there is no reason to show and then hide all
$('.content.item, .current.item').hide();
$('.item').not(this).fadeTo(0, 0.5);
$(this).fadeTo(0, 1.0);
});
check if this works for you
Edit another approch could be using index suffix in classes in loop
eg
you could use class1, class2, class3 instead.
$('.item.two').click(function(){
// this is the content i want to show on click
$('.content.itemTwo').show();
// this is the content that i want to hide/remain hiding on click
$('.content.itemOne, .content.itemThree, .content.itemFour').hide();
// these are icons representing the content
$('.item.one, .item.three, .item.four').fadeTo(0, 0.5);
$('.item.two').fadeTo(0, 1.0);
});
to
for(var i=1;i<=4;i++){
$('.item.'+i).click(function(){
// this is the content i want to show on click
$('.content.class'+i).show();
// this is the content that i want to hide/remain hiding on click
$('.content class').hide();
// these are icons representing the content
$('.item').not(this).fadeTo(0, 0.5);
$(this).fadeTo(0, 1.0);
});
}
Hope you can get approch from it
Use the push method like
var arrayClass = [];
$('.item.two').click(function() {
arrayClass.push($(this));
});
alert(arrayClass);
You mean you are trying to select a list of items using jQuery because you have been using a lot of clases? You can do this by using jquery index, with eq and the this selector.
Here is a full description on how to use the index feature to make your code shorter
http://api.jquery.com/index/
You do not have to repeat same class over and over and do not need to store classes in array.
Change
$('.content.item, .content.item, .content.item, .current.item, .current.item, .current.item').hide();
To
$('.content.item').hide();
You can store classes in string instead of array in this case $('.item.one, .item.three, .item.four')
classesSet = ".item.one, .item.three, .item.four";
$(strClassesSet).fadeTo(0, 0.5);

jQuery Toggle modification

I am using the below javascript (jQuery) to toggle open two DIVs. The DIVs open fine and open one at a time, which is what I am after. However, I also want the DIVs to close when they are clicked a second time, which doesn't happen despite my best efforts!
Javascript:
$(document).ready(function() {
$('.info_tab').click( function() {
var currentID = $(this).next().attr("id");
$('.toggle_info[id!=currentID]').hide(); /* the intention here is to hide anything that is not the current toggling DIV so as to close them as a new one is opened. I thought this would leave the currently selected DIV uninterrupted to toggle closed (below), but it doesn't */
$(this).next().toggle();
return false;
});
});
HTML:
<div class="info_tab">
<h1>Person One</h1><br />
<p>click for less info</p>
</div>
<div id="person_one_info" class="toggle_info">
<p>More information about Philip Grover</p>
</div>
<div class="info_tab">
<h1>Person Two</h1><br />
<p>click for less info</p>
</div>
<div id="person_two_info class="toggle_info">
<p>More information about Roy Lewis</p>
</div>
If any more info is needed, just ask and I'll be happy to edit the question.
Cheers,
Rich
you have the concept down, but not using the "currentID" correctly. You need to remember it's a variable, and can't be in another string if you want it evaluated.
With that said, try this:
$('.toggle_info[id!='+currentID+']').hide();
This makes the variable get evaluated in the selector, then passes it off to jQuery to find.
it looks like you're going to an accordian effect though. And jQuery UI has just such a control that you can use (if you're interested). if you're going for experience, then carry on. ;-)

Categories