I have this bit of Javascript that handles clicks on my navbar. It is working for the most part the disable style is being applied where it should be the previous next, first, and last buttons all take you to the correct page. For some reason the same technique applied to the active style is not working. Ideally I never want any buttons to show as active except the current page button. Whichever button I click shows as active though and the current page doesn't get the active style unless you click on it. Any help on the correct syntax to set and unset active on my Navbar buttons would be appreciated.
var current_page;
var total_pages;
function fnPage_click(multiplyer) {
//make all buttons inactive and enabled
for (var i = 0; i < total_pages; i++)
$('#li' + i).removeClass("active");
$('#li.prev').removeClass("active");
$('#li.prev').removeClass("disabled");
$('#li.next').removeClass("active");
$('#li.next').removeClass("disabled");
$('#li.first').removeClass("active");
$('#li.last').removeClass("active");
$.ajax({
url: '/Home/Browsing?' + multiplyer,
type: 'POST',
error: function (xhr) {
alert('Error: ' + xhr.statusText);
},
success: function (result) {
$("#divLocGrid").html(result);
current_page = multiplyer;
switch (current_page) {
case 1: {
//Previous is disabled/inactive, First is inactive, the current_page is active
$("#li.prev").removeClass("active").addClass("disabled");
$("li.first").removeClass("active");
$('#li' + current_page).addClass("active");
break;
}
case total_pages: {
//Next is disabled/inactive, Last is inactive, the current_page is active
$('#li.next').removeClass("active").addClass("disabled");
$("li.last").removeClass("active");
$('#li' + current_page).addClass("active");
break;
}
default: {
//Previous and Next are enabled but inactive the current_page is active
$('#li.prev').removeClass("active");
$('#li.next').removeClass("active");
$('li' + current_page).addClass("active");
break;
}
}
},
async: true,
processData: false
});
}
function fnPrevNxt(strDir) {
var multiplyer;
if (strDir == 'Nxt') {
multiplyer = current_page + 1;
if (multiplyer > total_pages) {
$('#li.next').removeClass("active").addClass("disabled");
return;
}
}
else {
multiplyer = current_page - 1;
if (multiplyer < 1) {
$('#li.prev').removeClass("active").addClass("disabled");
return;
}
}
fnPage_click(multiplyer);
}
function fnOnNavBtnsLoad(model) {
total_pages = model;
fnPage_click(1);
}
<body onload="fnOnNavBtnsLoad(#Model)">
<div id="dvNavBtns">
<nav class="navbar navbar-expand-lg bg-gray-light navbar-dark" aria-label="Locations pages">
<ul id="ulNavBtns" class="pagination">
<li id="li.first" class="page-item">
First
</li>
<li id="li.prev" class="page-item">
<a href="javascript:void(0)" id="btnPrev" aria-label="<<" class="page-link" onclick="fnPrevNxt('Prev')">
<span aria-hidden="true">«</span>
</a>
</li>
#{int pages = Model;
int num = 0;
while (num < pages)
{
num++;
<li id="li" +#(num) class="page-item">
<a href="javascript:void(0)" aria-label=#num class="page-link" onclick="fnPage_click(#(num))">
#(num)
</a>
</li>
}
}
<li id="li.next" class="page-item">
<a href="javascript:void(0)" id="btnNxt" aria-label=">>" class="page-link" onclick="fnPrevNxt('Nxt')">
<span aria-hidden="true">»</span>
</a>
</li>
<li id="li.last" class="page-item">
Last
</li>
</ul>
</nav>
</div>
Its kind of convoluted but this is the syntax that finally worked for me. I had to go through the document.context.all collection of elements to find the element then add or remove from the classList collection of the element.
$(document).context.all['li.id'].classList.add("classname");
$(document).context.all['li.id'].classList.remove("classname");
Related
I need to select two elements (two tabs of five within a web) for click over them and scrap the tables returned.
Each tab is a 'li' and its child is a 'span' that contains the onclick event. I always get the list of tabs with the correct number of them but only the first element is not null, and even in the first element I can't call the onclick event to show me its tables. Also the 'id' that contains the onclick event is random.
I using phantomjs 2.1.1 and casperjs 1.1.4
JS code:
//Wait to be redirected to the Home page, and then make a screenshot
casper.then(function(){
casper.wait(5000, function(){
this.capture('home.png');
var tabs = casper.evaluate(function() {
//return document.querySelectorAll('[id^="dbTabLabel_"]'); //Another selector option
return document.querySelectorAll('span.dashTitle');
}
console.log('Num Tabs: ' + tabs.length););
for(i = 0; i < tabs.length; i++) {
if(tabs[i]) {
console.log('Form exists');
console.log('form id: ' + tabs[i].id);
// create a mouse click event
var event = document.createEvent( 'MouseEvents' );
event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );
// send click to element
tabs[i].dispatchEvent( event );
var name = tabs[i].innerText + '.png'
casper.wait(2000, function(){ // Wait to load completely
this.capture(name); //Make a screenshot for each tab
});
} else {
console.log("Null Tab");
}
}
})
});
The output:
Num Tabs: 5
Form exists
form id: dbTabLabel_820718256523832
Null Tab
Null Tab
Null Tab
Null Tab
I want scrap this web (html code when I'm login in and save the web with getHTML casper function). The web screenshot here. And this is the fragment corresponding to the tabs:
<!--TEMPLATES-->
<ul id="tabul">
<li id="litab" class="ntabs add">+</li>
<li id="litab" class="add rightAlign setting-item">
<img src="/Content/images/icons/expand-24x24.png" class="out-triggerer gray" onclick="fullScreen()">
</li>
<li id="default-report-export" class="rightAlign">
<a href="/report/defaultExport" download="">
<input type="image" src="/Content/images/icons/excel.gif" value="Excel" title="Export default report">
</a>
</li>
<li id="default-report-export" class="rightAlign">
<a href="/report/defaultExport?isPdf=true" download="">
<input type="image" src="/Content/images/export-pdf-24x24.png" value="Excel" title="Export default report">
</a>
</li>
<li id="dbTab_889113733777776" class="ntabs addedTab activeTab">
<span id="dbTabLabel_889113733777776" class="dashTitle" onclick="clickDashboard('889113733777776')">Dashboard EUR</span>
<span id="dbTabSettings_889113733777776" class="settingsContainer dashSettings" style="">
<div id="topnav" class="topnav">
<a href="javascript:void(0)" class="signin" onclick="toggleTabSettingsMenu('889113733777776',true);">
<span><img src="/Content/Images/icon_gear.png" alt="Edit"></span>
</a>
</div>
<fieldset id="dbTabSettingsMenu_889113733777776" class="dashSettings-menu">
<ul class="dashboardEditMenu">
<img src="/Content/images/close.png" onclick="toggleTabSettingsMenu('889113733777776',false);" alt="tooltip" style="position:absolute;right:2px;top:2px;border:0;">
<li class="dashboardEditMenuList">
Añadir widgets
</li>
<li class="dashboardEditMenuList">
Borrar este dashboard
</li>
</ul>
</fieldset>
</span>
</li>
<li id="dbTab_894967889413237" class="ntabs addedTab">
<span id="dbTabLabel_894967889413237" class="dashTitle" onclick="clickDashboard('894967889413237')">Dashboard USD</span>
<span id="dbTabSettings_894967889413237" class="settingsContainer dashSettings" style="display:none;">
<div id="topnav" class="topnav">
<a href="javascript:void(0)" class="signin" onclick="toggleTabSettingsMenu('894967889413237',true);">
<span><img src="/Content/Images/icon_gear.png" alt="Edit"></span>
</a>
</div>
<fieldset id="dbTabSettingsMenu_894967889413237" class="dashSettings-menu">
<ul class="dashboardEditMenu">
<img src="/Content/images/close.png" onclick="toggleTabSettingsMenu('894967889413237',false);" alt="tooltip" style="position:absolute;right:2px;top:2px;border:0;">
...
</ul>
</fieldset>
</span>
</li>
</ul>
I don't know if my problem is if my problem is related to this post I have read. But the proposed solution I can't do it because my 'ids' are random and I can't make "static" selectors for get them.
it's not an issue with document.querySelectorAll() because you have the right number of tabs in console.log('Num Tabs: ' + tabs.length);
it's because of the asynchronous casper.wait() here's an answer about asynchronous process in a loop
The for loop runs immediately to completion while all your
asynchronous operations are started. When they complete some time in
the future and call their callbacks, the value of your loop index
variable i will be at its last value for all the callbacks.
one way to work this out is to use use es6's let instead of var like
for(let i = 0; i < tabs.length; i++) { ... ES6 var vs let
or use .forEach since it creates its own function closure
for vs .forEach()
replace your for(i = 0; i < tabs.length; i++) { with tabs.forEach(function(tab)) { ..
and access the tab with tab instead of tabs[i]
here's a snippet to demonstrate it :
var tabs = ['tab1', 'tab2', 'tab3', 'tab4']
for(var i = 0; i < tabs.length; i++){
if(tabs[i]){
setTimeout(function(){ // simulating casper.wait
console.log('in the for loop with var : ' , tabs[i]);
}, 1000);
}
else{
console.log('none');
}
}
for(let i = 0; i < tabs.length; i++){
if(tabs[i]){
setTimeout(function(){ // simulating casper.wait
console.log('in the for loop with let : ' , tabs[i]);
}, 1000);
}
else{
console.log('none');
}
}
tabs.forEach(function(e){
if(e){
setTimeout(function(){ // simulating casper.wait
console.log('in the forEach loop : ' , e);
}, 1000);
}
else{
console.log('none');
}
})
hi guys i need some help with javascript,
i have a toggle function for my text, waht you can see on www.jasperscheper.nl
but i want to make the text stay when you double click on over mij and home.
this is my code:
var bannerText1 = document.getElementById('bannertext1');
var bannerText2 = document.getElementById('bannertext2');
var displayedBannerText = 1;
function toggleBannerText() {
if(displayedBannerText == 1) {
// Switch to bannertext 2
bannerText1.className += ' hidebannertext';
displayedBannerText = 2;
bannertext2.className = 'welkom';
} else {
bannertext2.className += ' hidebannertext';
displayedBannerText = 1;
bannerText1.className = 'welkom';
}
}
<li class="knop" >
<button class="button" href="#"onclick="toggleBannerText()"> <h3>Home</h3></button>
</li>
<li class="knop">
<button class="button" onclick="toggleBannerText()" href="#"><h3>Over mij</h3></button>
</li>
thanks in advance,
Jasper Scheper.
Problem: You are calling the function toggleBannerText() every time there is a click on any of the buttons, There is no where the button's click events are distinguished, So every click assumes you need to show other text than the one shown.
Solution: Change your HTML to pass a parameter into the function saying which section it wants to show. Eg: toggleBannerText('Home')
<li class="knop" >
<button class="button" href="#"onclick="toggleBannerText('Home')"> <h3>Home</h3></button>
</li>
<li class="knop">
<button class="button" onclick="toggleBannerText('Over')" href="#"><h3>Over mij</h3>
</button> <!-- There was a typo you had a </a> here I changed it -->
</li>
Now change your function to accept the parameter and show that particular Text .
function toggleBannerText(section) {
if(section === "Over") {
// Switch to bannertext 2
bannerText1.className = 'hidebannertext'; // I have removed the +
bannertext2.className = 'welkom';
}
else if (section === "Home"){
bannertext2.className = 'hidebannertext'; // + has been removed
bannerText1.className = 'welkom';
}
else{
// none of the two buttons were clicked.
}
}
I have tested this code against your site and its working fine
Trying to add a class to an element inside an li item when a function call is made. I can get the correct value outputted, however finding the child <i> is proving difficult. If I could find the correct nested <i> and add the class 'show' that would solve it :)
JS code:
filterMarkers = function(category) {
for (i = 0; i < markers1.length; i++) {
marker = gmarkers1[i];
// If is same category or category not picked
if (marker.category == category || category.length === 0) {
marker.setVisible(true);
// Show the tick icon
$(".filter").find("[data-value='" + category + "']").addClass('show');
}
// Categories don't match
else {
marker.setVisible(false);
}
}
}
HTML code:
<ul class="drop-down">
<li class="filter blue" data-value="" onclick="filterMarkers('');">All <i class="fi-check"></i></li>
<li class="filter yellow" data-value="test-one" onclick="filterMarkers('test-one');">Sales <i class="fi-check"></i></li>
<li class="filter red" data-value="test-two" onclick="filterMarkers('test-two');">Incentives <i class="fi-check"></i></li>
<li class="filter grey" data-value="test-three" onclick="filterMarkers('test-three');">Conferences <i class="fi-check"></i></li>
<li class="filter orange" data-value="test-four" onclick="filterMarkers('test-four');">Team building <i class="fi-check"></i></li>
</ul>
Looking at the filterMarkers method, you
Either want to simply show the category which is passed as argument and hide everything else
Or if no argument is passed then hide everything.
Simplify your code to
filterMarkers = function(category) {
$(".filter").removeClass("show"); //remove show class from all
if( category.length > 0 )
{
$(".filter[data-value='" + category + "']").addClass('show');
}
for (i = 0; i < markers1.length; i++)
{
marker = gmarkers1[i];
marker.category == category || category.length === 0 ? marker.setVisible( true ) : marker.setVisible( false );
}
}
}
$(".filter[data-value='" + category + "']").addClass('show');
The following code works, but I think there's room for improvement. The index check is there because after the first element is removed the next element looks like it has an index of -1, but is actually the previously removed element. Then it iterates again and finds the clicked element and removes it. BUT since the index is -1 on the first go around the wrong group gets deleted.
How do I keep the zombie elements from being iterated on more efficiently? This is in a backbone view with an in page confirmation.Thanks.
EDIT: To add HTML
Group section always has a default group that shouldn't be deleted.
<div class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>All Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div><!--/expandable__content-->
Tag section to remove groups
<div class="js-favorite-doctor-manage-add-remove">
<div class="grid-construct">
<div class="expandable" data-controller="expandable">
<ul class="tag-list js-group-list" tabindex="-1">
<li class="tag tag--teal" >
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li class="tag tag--teal" >
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
</ul>
</div>
removeGroup: function( evt ) {
var deleteGroup = function() {
if ( $(evt.currentTarget).closest('.tag').hasClass('is-active')){
var clickedTag = $(evt.currentTarget).closest('.tag');
var groupList = this.$el.find('.js-group-list');
var groupTags = groupList.find('.tag');
var index = groupTags.index(clickedTag);
var groupSections = $('.js-favorite-group');
// add one to account for "All" section which is never removed
var groupToRemove = groupSections.eq(index + 1);
console.log(groupToRemove);
var removedGroupName = this.getGroupNameForSection(groupToRemove);
var allDoctors = groupSections.eq(0);
var allDoctorsContainer = allDoctors.find('.js-favorite-doctor-row-container');
if ( index > -1 ){
groupToRemove.find('.js-favorite-doctor-row').appendTo(allDoctorsContainer);
clickedTag.remove();
groupToRemove.remove();
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
};
this.showAlert(evt, deleteGroup);
},
showAlert: function (evt, callback) {
that = this;
var clickedTag = '';
clickedTag = $(evt.currentTarget).closest('.tag');
clickedTag.addClass('is-active').attr('data-delete','true');
$('.delete-acct-message').show().focus();
$('.js-remove-yes').on('click', function(evt){
evt.preventDefault();
callback.apply(that);
});
$('.js-remove-no').on('click', function(evt){
evt.preventDefault();
this.hideConfirm(evt);
});
},
I would suggest that you should use custom attributes in your html, this will simplify your javascript logic and make it more effective and efficient.
I have modified your html and javascript to add the support for custom attribute data-doc-group. Have a look at your group sections div here
<div data-doc-group="lauren" class="section-border-top--grey js-favorite-group">
<h4 class="expandable__cta cta--std-teal js-expand-trigger"><span class="icon icon-plus--teal expandable__cta-icon"></span>Lauren's Doctors</h4>
<div class="expandable__content js-favorite-doctor-row-container" aria-expanded="true">
<div class="location-section dr-profile">
<div class="section__content js-doctor-row">
<div class="favorite-doctor-manage__row">
DR info
</div>
</div><!--/section__content-->
</div><!--/location-section-->
</div>
Here are the tags with custom attributes
<li data-doc-group="lauren" class="tag tag--teal">
Lauren's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Lauren's Doctors</button></li>
</ul>
</li>
<li data-doc-group="timmy" class="tag tag--teal">
Timmy's Doctors
<ul class="tag-sub">
<li><button class="tag-icon tag-icon--close-white js-group-remove">Remove group: Timmy's Doctors</button></li>
</ul>
</li>
Here is the javascript to handle this, (this may be a bit buggy, but will give you a general idea)
removeGroup: function(evt) {
this.showAlert(evt, function() {
var $clickedTag = $(evt.currentTarget).closest('.tag'),
dataGroupName,
$groupToRemove,
removedGroupName,
$allDoctors = $('.js-favorite-group').eq(0),
$allDoctorsContainer = $allDoctors.find('.js-favorite-doctor-row-container');
if ($clickedTag.hasClass('is-active')){
dataGroupName = $clickedTag.data('doc-group');
$groupToRemove = $allDoctors.siblings('[data-doc-group="' + docGroupName + '"]');
if ($groupToRemove.length > 0){
$groupToRemove.find('.js-favorite-doctor-row').appendTo($allDoctorsContainer);
$clickedTag.remove();
$groupToRemove.remove();
removedGroupName = this.getGroupNameForSection($groupToRemove);
this.updateSectionDropdowns();
this.ariaAlert('Group ' + removedGroupName + ' removed');
this.hideConfirm(evt);
}
}
});
}
I have the following html structure:
<div id="gw-sidebar" class="gw-sidebar">
<div class="nano-content">
<ul class="gw-nav gw-nav-list">
<li class="init-un-active"> <span class="gw-menu-text">Scenarios</span> </li>
//===>Need to add the new list using Jquery here
</ul>
</div>
</div>
I want to add a list as shown below using jquery to the class 'init-un-active' shown above:
<li class="init-arrow-down"> <span class="gw-menu-text">Scenario-1</span> <b class="gw-arrow"></b>
<ul class="gw-submenu">
<li> Scenario </li>
<li> Resolutions </li>
<li> Triggers </li>
</ul>
</li>
How do i use jquery to add this code dynamically to the aforementioned class?
I have tried the following but it wont work:
<script type="text/javascript">
function loadScenarioForm () {
SideMenu.createBaseEntry();
// ScenarioForm.create();
}
var SideMenu = {
container : null,
scenarioCount : 0,
scenarioTxt : "Scenario",
ResolutionsTxt : "Resolutions",
TriggersTxt : "Triggers",
menuLink : "javascript:void(0)",
subMenuLink1 : "javascript:void(0)",
subMenuLink2 : "javascript:void(0)",
subMenuLink3 :"javascript:void(0)",
createBaseEntry : function createDefault () {
this.container = $(document.createElement('div'));
this.container.addClass('gw-sidebar');
var html = "";
html += '<div id="gw-sidebar" class="gw-sidebar">';
html += '<div class="nano-content">';
html += '<ul class="gw-nav gw-nav-list">';
html += '<li class="init-un-active"> <span class="gw-menu-text">Scenarios</span> </li>';
html += '</ul></div></div></div>';
this.container.append(html);
$('body').append(this.container);
this.scenarioCount++;
this.container.append(this.createEntry(scenarioCount));
},
createEntry : function createDefault (index) {
var list = $('ul.mylist');
var li = $('<li/>')
.addClass('ui-menu-item')
.attr('role', 'menuitem')
.appendTo(list);
return list;
},
</script>
Please advise,
Thanks!
You can make your <li> as a template and append it to the <ul> using jquery. You can try something like this Fiddle:
$(document).ready(function(){
$('a').click(function() {
var template = $('#hidden-template').html();
$('.gw-nav').append(template);
});
});
if ($(".init-un-active").length == 0) {
$.ajax({
url: 'URL From where you want to load ...',
type: 'POST',
data: { id: ID}, // pass your data here if any .. else keep empty
success: function (data) {
$(".init-un-active").css({ "display": "block", "z-index": "999999999999" });
$(".init-un-active").html(data);
},
error: function () {
alert('Unable to load menu...');
}
});
}
else {
if ($(".init-un-active ul").length > 0) {
$(".init-un-active ul").css("display", "none");
$(".init-un-active").css("display", "block");
}
}
Explanation:
if ($(".init-un-active").length == 0)
This condition is used to check if there are already item loaded in li .. if yes then no need to call ajax.. just hide show that menu..
$(".init-un-active").css({ "display": "block", "z-index": "999999999999" });
this css is applied to show menu infront and hide all content beside this menu..
this.container.append(html);
$('body').append(this.container);
instead of this try this
$(".init-un-active").html(html);