Jquery can't change the classname after one time - javascript

Here is my code for Dropdown Menu Appear and Disappear..
If the class name is "dropdown pull-right" then the menu will be closed
If the class name is "dropdown pull-right open" then the menu will be opened
<li class="dropdown pull-right" id="tobechanged">
<a data-toggle="dropdown" class="dropdown-toggle" aria-expanded="false">
<i class="fa fa-user"></i> Admin <b class="caret"></b>
</a>
</li>
So, i wrote this query
$(".dropdown-toggle" ).click(function() {
console.log(document.getElementById("tobechanged").className);
if (document.getElementById("tobechanged").className == "dropdown pull-right" ) {
console.log('opening menu');
document.getElementsByClassName("dropdown-toggle").className = "dropdown pull-right open";
}
else
{
console.log('closing menu');
document.getElementsByClassName("dropdown-toggle").className = "dropdown pull-right";
}
});
It works only in the first time. If i change to another page only the console console.log('opening menu'); works and the class name is changing..
What is the mistake i am doing and how can i make the class name change ?
Note : I am using angularjs, so the page won't be reloaded entirely

I think you should change the Class of the Parent li Element not the a Element inside it.

The issue I see is that once you execute the line:
document.getElementsByClassName("dropdown-toggle").className = "dropdown pull-right open";
This basically will change your html from :
<li class="dropdown pull-right" id="tobechanged">
<a data-toggle="dropdown" class="**dropdown-toggle**" aria-expanded="false">
<i class="fa fa-user"></i> Admin <b class="caret"></b>
</a>
</li>
into
<li class="dropdown pull-right" id="tobechanged">
<a data-toggle="dropdown" class="**dropdown pull-right open**" aria-expanded="false">
<i class="fa fa-user"></i> Admin <b class="caret"></b>
</a>
</li>
Making basically your element no longer available for click event, because the click is subscribed to an element by class name which you change.
$(".dropdown-toggle" )
Hope this is not too confusing.

A fix plus some additional improvements; no need to search for the elements a couple of times
$(".dropdown-toggle" ).click(function() {
var el = document.getElementById("tobechanged");
if (el.className == "dropdown pull-right" ) {
console.log('opening menu');
el.className = "dropdown pull-right open";
}
else {
console.log('closing menu');
el.className = "dropdown pull-right";
}
});
To do it in in JQuery :
$(".dropdown-toggle" ).click(function() {
$(this).closest('#tobechanged').toggleClass('open');
});
Update:
Demo https://jsfiddle.net/n13svnLL/

<pre>you are assigning class name only for dropdown-toggle so it will work only one time for that you have to assign same class name to id (tobechanged) as well</pre>
if (document.getElementById("tobechanged").className == "dropdown pull-right" ) {
console.log('opening menu');
document.getElementsByClassName("dropdown-toggle").className = "dropdown pull-right open";
document.getElementById("tobechanged").className == "dropdown pull-right open";
}
else
{
console.log('closing menu');
document.getElementsByClassName("dropdown-toggle").className = "dropdown pull-right";
document.getElementById("tobechanged").className == "dropdown pull-right"
}

Related

Don't hide dropdown list when clicked inside it

I've made this dropdown menu using bootstrap. The problem is that it hides itself when I click inside it or check a checkbox inside it as well. How do I get it not to close unless clicked somewhere outside the dropdown.
Thanks in advance!
<div class="ibox-tools">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="true">
<i class="fa fa-line-chart"></i>
</a>
<ul class="dropdown-menu dropdown-user" style="width:200px">
#foreach(PKG_VLTROUTINE_GET_EXCHAGEINFO_Result cur in Model)
{
<li style="padding:5px">
<strong>#cur.VLTNAME</strong>
#cur.RATE
<br />
<small>#cur.VLTFULLNAME</small>
<small>
(
#cur.RATEDIF
#if (cur.DIRECTION == 1)
{
<i style="color:#1ab394" class="fa fa-level-up text-navy"></i>
}
else
{
<i style="color:#ed5565" class="fa fa-level-down text-navy"></i>
}
)
</small>
<div class="MsSwitch MsSwitch-update">
<input data-evoldvall="-1" value="-1" type="checkbox" checked="" data-valtrue="-1" data-valfalse="" name="#cur.VLTNAME" class="evCheckBox">
<label for="#cur.VLTNAME"></label>
</div>
<li class="divider" style="margin:0px"></li>
</li>
}
</ul>
Remove the data attribute data-toggle="dropdown" and implement the open/close of the dropdown can do the job.
First handle the click on the link to open/close the dropdown like this :
$('a.dropdown').on('click', function () {
$(this).parent().toggleClass('open');
});
Then wait for the clicks outside of the dropdown to close it like this :
$('body').on('click', function (e) {
if (!$('a.dropdown').is(e.target) && $('a.dropdown').has(e.target).length === 0 && $('.open').has(e.target).length === 0 ) {
$('a.dropdown').parent().removeClass('open'); } });

Dynamically change text of button with javascript

I have a dropdown list with 5 elements which are displayed inside the button when pressed.
Right now, the button gets the value of selected tab but I want it to have a default text before this value; this text should be "Filter by:" value. And I also need that caret to be displayed...Any ideas how I can get this working?
HTML:
<div class='filtering_options dropdown'>
<button class="btn bet-filter btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">Filter by:
<span class="caret"></span>
</button>
<ul class="dropdown-menu CHECK-HEIGHT" aria-labelledby="dropdownMenu1">
<li><a href='#brzn/yolo/all' class='btn btn-filter all' data-filter='all'>{{translate 'bets_filter_all'}}</a></li>
<li><a href='#brzn/yolo/open' class='btn btn-filter open' data-filter='open'>{{translate 'bets_filter_open'}}</a></li>
<li><a href='#brzn/yolo/closed' class='btn btn-filter closed' data-filter='closed'>{{translate 'bets_filter_closed'}}</a></li>
<li><a href='#brzn/yolo/pending' class='btn btn-filter pending' data-filter='pending'>{{translate 'bets_filter_ended'}}</a></li>
<li><a href='#brzn/yolo/resolved' class='btn btn-filter resolved' data-filter='resolved'>{{translate 'bets_filter_resolved'}}</a></li>
</ul>
</div>
JS with coffeescript:
filter: (filter)->
# set default values for the filter
if _.isEmpty(filter)
filter = #default_filter
if filter.dir
filter.dir = parseInt(filter.dir) || 0
if !(filter.status in ['all', 'open', 'closed', 'pending', 'resolved'])
filter.status = 'all'
prev_filter = #filter_options
#filter_options = _.extend({}, #default_filter, filter)
if _.isEqual(#filter_options, prev_filter)
return
#update_comments(#filter_options)
#$('.btn-filter.active').not(".btn-filter.#{filter.status}").removeClass('active')
#$(".btn-filter.#{filter.status}").addClass('active')
#$(".bet-filter").text(filter.status)
Found the solution by myself:
Created a new translation for 'Filter by'
Concatenate this translation with value
#$(".bet-filter").text((#app.translate('filter_by')) + (filter.status))

How to enable up and down arrow keys in bootstrap dropdown

Bootstrap 3 panel title contains dropdown using code below.
If dropdown is opened, up and down arrows do not move between items.
How to enable dropdown navigation using up and down arrow keys ?
<div class="panel panel-success grid-panel-header">
<div id='contentCaptionDiv' class="panel-heading">
<div class="panel-title form-inline">
<a class="btn" href="Show">
<i class="fa fa-male" aria-hidden="true"></i>
</a>
<a class="btn" href="Delete">
<i class="fa fa-female" aria-hidden="true"></i>
</a>
<div class="dropdown" type="button">
<div class="dropdown-toggle" data-toggle="dropdown" role="button" href="#">
<i class="glyphicon glyphicon-cog"></i>
<span class="caret"></span>
</div>
<ul class="dropdown-menu" role="menu">
<li>Action</li>
<li>Another action</li>
<li>Something else here</li>
</ul>
</div>
</div>
panel content here
</div>
The reason that you code doesn't work is because you use a <div> for .dropdown-toggle.
Make it a <button> and it will work.
Strange enough, not even this kind of element works: span.btn.btn-default.
Another reason that do not apply to your case:
Make sure your <a> elements inside the <li>s have an attribute of href="#" or href="" (ir that the attribute exists, in general).
href="#" works indeed for arrow keys. Using this causes page 404 redirect on item select. If you are not looking to redirect to another page use this work around: href="javascript:" instead of href="#"
<script type="text/javascript">
$(document).keydown(function(e) {
if(e.which == 40 || e.which == 38) {
openNavbar = $(".dropdown.open");
if(openNavbar[0]) {
menu = openNavbar.children(".dropdown-menu");
menu.find("a").css("outline", "none"); // remove the pesky blue outline
hovered = menu.find("li:hover");
if(hovered[0]) {
if(e.which == 40) hovered.next().children().focus();
else hovered.prev().children().focus();
}
else menu.find("li").first().children().focus();
}
}
});
</script>
I haven't found a built in solution, but I have made a snippet, that seems to do the job.

jquery tree plugin expanding items

I have some html that looks like this:
<div class="list-group">
<a id="427" href="#" class="list-group-item"><i class="fa indent0 fa-caret-down"></i>Home</a>
<a id="428" href="#" class="list-group-item"><i class="fa fa-caret-right indent1"></i>Images</a>
<a id="429" href="#" class="list-group-item"><i class="fa fa-caret-right indent1"></i>Videos</a>
<a id="430" href="#" class="list-group-item"><i class="fa indent1 fa-caret-right"></i>Documents</a>
<a id="431" href="#" class="list-group-item" style="display: none;"><i class="fa fa-caret-right indent2"></i>Sub category</a>
<a id="432" href="#" class="list-group-item" style="display: none;"><i class="fa indent2 fa-caret-down"></i>Another sub</a>
<a id="433" href="#" class="list-group-item" style="display: none;"><i class="fa fa-caret-right indent3"></i>Super sub</a>
<a id="434" href="#" class="list-group-item" style="display: none;"><i class="fa fa-caret-right indent2"></i>asdfasdf</a>
<a id="435" href="#" class="list-group-item" style="display: none;"><i class="fa fa-caret-right indent2"></i>asdf</a>
<a id="436" href="#" class="list-group-item"><i class="fa fa-caret-right indent1"></i>Audio</a>
</div>
when I click the .fa I want it to get the indent plus 1 between itself and the next item with the same indent class to unhide.
So in this case,
if we press on id 430, it will show 431, 432, 434 and 435.
Now, that is the easy part. What I need it to also do, is check of any element between 430 and 436 (in this case) and if any of the elements have the class fa-caret-down then it shows the children of that too.
Currently I have made this into a plugin and my code actually works, but I think it could be a lot neater.
I am hoping that some of your gurus will see a simpler solution.
Here is my solution currently:
events: function () {
var self = this;
$(self.element).on("click", ".fa", function (e) {
e.stopPropagation();
var $target = $(this);
var indent = $target.prop('className').match(/\b(indent\d+)\b/)[1];
if ($target.hasClass("fa-caret-right")) {
$target.removeClass("fa-caret-right").addClass("fa-caret-down");
self.showChildren($target.parent(), indent);
if (typeof self.options.onItemExpand === "function") {
self.options.onItemExpand.apply(this, arguments);
}
} else {
var $children = $target.parent().nextUntil("a:has(." + indent + ")");
$target.removeClass("fa-caret-down").addClass("fa-caret-right");
$children.hide();
if (typeof self.options.onItemContract === "function") {
self.options.onItemContract.apply(this, arguments);
}
}
})
},
showChildren: function ($target, className) {
var self = this;
var num = parseInt(className.match(/(\d+)$/)[1], 10);
var $children = $target.nextUntil("a:not(:has(.indent" + (num + 1) + "))");
$.each($children, function (i, item) {
var $item = $(this).find(".fa");
if ($item.hasClass("fa-caret-down")) {
var indent = $item.prop('className').match(/\b(indent\d+)\b/)[1];
self.showChildren($(this), indent);
}
});
$children.show();
}
My solution nearly works (although I hope someone can make it neater) but there is an issue.
If you click Home it will hide all (as expected) but if you click to show again, it will show all but Audio. The same thing happens if you expand down to Documents > Another sub > Super sub and expand that. When you contract it, Audio will vanish.
http://jsfiddle.net/sn92W/
I assume this is to do with nextUntil.
Please help :)

Select text from div - the not obvious way

Here is my div :
<div id="myDiv">The
<span class="cordial-err-corr" id="good0-0" data-original-title="" title="">best</span>
way to receive congrats
<span>
<span class="cordial-err-corr" id="good0-1" data-original-title="" title="">are</span>
<div class="btn-group">
<a class="btn btn-mini dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a class="prop0-1">is</a></li>
<li><a class="prop0-1">are</a></li>
</ul>
</div>
</span> to give a correct answer.</div>
I would like to get this text : "The best way to receive congrats are to give a correct answer."
So I call $('#myDiv').text(). It does not work since I get the two elements in ul.dropdown-menu.
The next step is to filter or remove the un-wanted children, i.e.:
<div class="btn-group">
<a class="btn btn-mini dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a class="prop0-1">is</a></li>
<li><a class="prop0-1">are</a></li>
</ul>
</div>
I tried to play with $.filter or $.not or $.children with jquery selectors, etc. I cannot find the correct way to do this. Need help!
You can find some code in jsfiddle : http://jsfiddle.net/Ku7FY/
[EDIT]
One solution suggests this code :
$('#result').append( $('#myDiv').text().replace($(".btn-group").text(),"") ).append('<br />')
If several div.btn-group exists, just loop as :
var result = $('#myDiv').text();
$(".btn-group").each(function() {
result = result.replace($(this).text(),"");
});
$('#result').append(result).append('<br />')
So, if I get this straight, you want to exclude the list from the .text(). Try something like:
$('#result').append( $('#myDiv').text().replace($(".dropdown-menu").text(),"") ).append('<br />')
If you don't mind placing all the "dumb" text in spans, then you can do it very simply by only grabbing "dumb" text spans and ".cordial-err-corr" spans (and a find()).
<div class="well" id="myDiv"><span class="cordial-content">The </span>
<span class="cordial-err-corr" id="good0-0" data-original-title="" title="">best </span>
<span class="cordial-content">way to receive congrats </span>
<span>
<span class="cordial-err-corr" id="good0-1" data-original-title="" title="">are </span>
<div class="btn-group">
<a class="btn btn-mini dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a class="prop0-1">is</a></li>
<li><a class="prop0-1">are</a></li>
</ul>
</div>
</span> <span class="cordial-content">to give a correct answer. </span></div>
and
$('#myDiv').find('.cordial-err-corr,.cordial-content').text()
Demo: Fiddle
I have an ugly, though simple enough (I guess) method:
We can make a copy, then remove the dom elements we don't want to display. Then we can get the desired text.
var clone_div = $('#myDiv').clone();
clone_div.find('.btn-group').remove();
$('#result').append(clone_div.text()).append('<br />');
Here is jsfiddle. http://jsfiddle.net/Ku7FY/4/
Try
function process(el){
var array = [];
$(el).contents().each(function(){
var $this = $(this), text;
if(this.nodeType == 3){
text = $.trim($this.text());
if(text){
array.push(text)
}
} else if($this.is(':not(.btn-group)')){
Array.prototype.push.apply(array, process(this))
}
})
return array;
}
console.log(process($('#myDiv')).join(' '))
Demo: Fiddle

Categories