I have this wizard step form that I simulated with <ul> list items by overlapping inactive <li> items with absolute positioning.
The wizard form is working as desired except that I want to hide next or previous button on a certain step.
This is my logic in jQuery but it doesn't do any good.
if (index === 0) {
$('#prev').addClass(invisible);
$('#prev').removeClass(visible);
} else if (index === 1) {
$('#prev').addClass(visible);
$('#prev').removeClass(invisible);
} else {
$('#next').addClass(invisible);
}
To get the index value I used eq() chained on a current step element like the following
var current;
var index = 0;
$(function () {
current = $('.pg-wrapper').find('.current');
$('#next').on('click', function() {
if (current.next().length===0) return;
current.next().addClass('current').show();
current.removeClass('current').hide();
navstep.next().addClass('active');
navstep.removeClass('active');
current = current.next();
navstep = navstep.next();
index = current.eq();
});
I tried to isolate it as much as possible but my full code will give you a better idea.
If you would care to assist please check my JS BIN
There were several issues
you used .eq instead of index
you were missing quotes around the class names
your navigation logic was flawed
no need to have two classes to change visibility
I believe the following is an improvement, but let me know if you have questions.
I added class="navBut" to the prev/next and rewrote the setting of the visibility
Live Demo
var current;
var navstep;
$(function () {
current = $('.pg-wrapper').find('.current');
navstep=$('.nav-step').find('.active');
$('.pg-wrapper div').not(current).hide();
setBut(current);
$('.navBut').on('click', function() {
var next = this.id=="next";
if (next) {
if (current.next().length===0) return;
current.next().addClass('current').show();
navstep.next().addClass('active');
}
else {
if (current.prev().length===0) return;
current.prev().addClass('current').show();
navstep.prev().addClass('active');
}
current.removeClass('current').hide();
navstep.removeClass('active');
current = (next)?current.next():current.prev();
navstep = (next)?navstep.next():navstep.prev();
setBut(current);
});
});
function setBut(current) {
var index=current.index();
var max = current.parent().children().length-1;
$('#prev').toggleClass("invisible",index<1);
$('#next').toggleClass("invisible",index>=max);
}
The eq function will not give you the index, for that you need to use the index() function.
I have not looked at the whole code but shouldn't your class assignemnts look like:
$('#prev').addClass('invisible');
$('#prev').removeClass('visible');
i.e. with quotes around the class names? And is it really necessary to have a class visible? Assigning and removing the class invisible should easily do the job (provided the right styles have been set for this class).
You should make 4 modifications.
1) Use .index() instead of .eq();
2) Add a function changeIndex which changes the class depends on the index and call it on click of prev and next.
3) add quotes to invisible and visible
4) There is a bug in your logic, try going to 3rd step and come back to 1st step. Both buttons will disappear. So you have to make next button visible if index = 0
Here is the demo :
http://jsfiddle.net/ChaitanyaMunipalle/9SzWB/
Use index() function instead of eq() because eq() will return object and index() will return the integer value.
DEMO HERE
var current;
var navstep;
var index = 0;
$(function () {
current = $('.pg-wrapper').find('.current');
navstep=$('.nav-step').find('.active');
$('.pg-wrapper div').not(current).hide();
}(jQuery));
$('#next').on('click', function() {
if (current.next().length===0) return;
current.next().addClass('current').show();
current.removeClass('current').hide();
navstep.next().addClass('active');
navstep.removeClass('active');
current = current.next();
navstep = navstep.next();
index = current.index();
change_step(index)
});
$('#prev').on('click', function() {
if (current.prev().length===0) return;
current.prev().addClass('current').show();
current.removeClass('current').hide();
navstep.prev().addClass('active');
navstep.removeClass('active');
current = current.prev();
navstep = navstep.prev();
index = current.index();
change_step(index)
});
function change_step(value)
{
if (value === 0) {
$('#prev').hide();
$('#next').show();
} else if (value === 1) {
$('#prev').show();
$('#next').show();
} else {
$('#next').hide();
$('#prev').show();
}
}
Related
I am a beginner coder and I'm trying to change the background color of a div based on how far down scrolled the webpage is, where am I going wrong?
Do I need to put in something to call the scrollTop amount?
(function () {
var scroll = .scrollTop;
if (scroll > 50) {
document.getElementByClassName("shop").style.backgroundColor = '#99C262';
}
else
{
document.getElementByClassName("shop").style.backgroundColor = ‘red’;
}
})();
Lose the dot, instead of “.shop” go for “shop”
And the actual function getElementsByClassName and it returns a collections of divs with the class name. But you need the first one (assuming you have only one such div) hence the 0 index in array
parentDOM.getElementsByClassName('test')[0].style.backgroundColor = "red";
<p class="test">hello here</p>
Many errors in the code....
var scrole = .scrollTop; not sure if you are trying to assign any value or is it window.scrollTop.
document.getElementByClassName(".shop") should be changed to document.getElementByClassName("shop")
else if (scroll < 50 ){ //statement } to be changed to else { //statement }
function is wrapped in small bracket but has never been invoked.
Self invoking function example :-
(function(){
console.log(Math.PI);
})();
Using a dot before a class name when getting it in javascript using getElementsByClassName is an Incorrect Syntax. Below is the correct syntax.
document.getElementsByClassName("shop")
Tip: Always Use the console window to monitor your Syntax and other errors.
Your code are only executed once if you don't attach a listener. Let me just use these code from MDN docs with a bit of edit. The docs
let last_known_scroll_position = 0;
let ticking = false;
function doSomething(scroll_pos) {
if (scroll_pos > 50) {
document.querySelector(“.shop”).style.backgroundColor = '#99C262';
} else if (scroll_post < 50) {
document.querySelecttor(“.shop”).style.backgroundColor = ‘red’;
} else {
// add more colorrrs!
}
}
window.addEventListener('scroll', function(e) {
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(last_known_scroll_position);
ticking = false;
});
ticking = true;
}
});
I am using the below code to render the same as many as times,
I have two sections, one section with show-all class and another with no class.
When 'show-all' class is not available, it need to run countIncrease function, if class available no need to run the function,
In every time section need to check whether the class is available or not.
class Grid {
init() {
$('.grid').each(function() {
const $this = $(this);
// getting values & url from from html
const dropDownUrlpath = $this.find('.grid__dropdown-select').attr('data-ajaxurl');
const hasClass = $this.find('.grid').hasClass('grid_showall');
// countIncrease shows the inital 6 compoents/div and rest of will be hidden
// onclick it will display 3 components/div
function countIncrease() {
let limit = parseInt($this.find('.grid__component').attr('data-initcount'), 10);
const incrementalCall = parseInt($this.find('.grid__component').attr('data-incrementalcount'), 10);
$this.find(`.grid__content > .grid__component:gt(' ${limit - 1} ') `).hide();
if ($this.find('.grid__content > .grid__component').length <= limit) {
$this.find('.grid__cta').hide();
}
else {
$this.find('.grid__cta').show();
}
$this.find('.grid__cta').on('click', function(event) {
event.preventDefault();
limit += incrementalCall;
$this.find(`.grid__content > .grid__component:lt(' ${limit} ')`).show();
if ($this.find('.grid__content > .grid__component').length <= limit) {
$this.find('.grid__cta').hide();
}
});
}
if (hasClass.length === true ) {
console.log('class exist-----'+ hasClass);
countIncrease();
}
// on dropdown change taking the selected dropdown value and adding #end of the url and replacing the previous html
$this.find('.grid__dropdown-select').on('change', function() {
const optionValue = this.value;
$.ajax({
url: dropDownUrlpath + optionValue,
success(result) {
$this.find('.grid__content').html(result);
countIncrease();
}
});
});
});
}
}
I written if condition, but it running once and giving false condition in both the scenarios,
if (hasClass.length === true ) {
console.log('class exist-----'+ hasClass);
countIncrease();
}
How to handle it...?
shouldnt you add a parameter to the .hasClass so it knows what to check?
if ( $this.hasClass ('some class') === true ) {
alert('something');
}
or set if(hasClass.length > 0){}
keep the checking class in a variable by finding with parent div,
const hasClass = $this.find('.grid').hasClass('grid_showall');
gets the attribute value for only the first element in the matched set with .attr() method
const classInthis = hasClass.attr('class');
check the condition, with
if (classInthis !== 'grid_showall') {
countIncrease();
}
$('.checkbox').on('change', function() {
$('.pagination').hide();
$('.callout').hide();
$('.checkbox').each(function() {
if ($(this).prop('checked') === true) {
var checkboxName = $(this).val();
$('.callout').each(function() {
var calloutArray = $(this).data();
var i;
for (i = 0; i < calloutArray.category.length; i++) {
$(this).hide();
if (checkboxName === calloutArray.category[i]) {
$(this).show();
}
}
});
}
});
});
To explain this function it basically listens to see if a checkbox has been clicked and then hides all the callouts on the page.
It then loops through each one of those checkboxes and checks which ones are true on the page. I then create a variable that stores the current checkbox value.
After this I then want to loop through each callout and pull its data from a data attribute.
I then loop through each string in the array and hide the callout no matter what. However if the callout has an array value that is the same as the checkbox value then I need to show it.
This seems to be working without the hide. However I need to hide the callouts if they do not hold the same checked category names which is where I'm running into problems.
The If statement seems to never return true if I have already hidden the callout. So the question is how do I show the callout if the selected checkboxes match one of the callout array strings but hide the callout if the string is not in the callout array.
From what I've understand, the following code is equivalent
$('.checkbox').on('change', function () {
$('.pagination, .callout').hide();
$('.checkbox:checked').each(function () {
var checkboxName = $(this).val();
$('.callout').hide().each(function () {
var calloutArray = $(this).data();
if (calloutArray.category.indexOf(checkboxName) !== -1) {
$(this).show();
}
});
});
});
Merge selectors having common actions(hide())
Use :checked pseudo-selector to select only checked elements
Use hide() on selector and then iterate over it using each()
Use indexOf to check if element is in array
You're showing/hiding your element on each iteration of the loop. That means the result of the last iteration wins, as though you hadn't done the earlier ones at all.
You can just use Array#indexOf to see if the name is in the array, and use the resulting flag to show/hide the callout:
$(this).toggle(calloutArray.category.indexOf(checkboxName) != -1);
E.g.:
$('.checkbox').on('change', function() {
$('.pagination').hide();
$('.callout').hide();
$('.checkbox').each(function() {
if ($(this).prop('checked') === true) {
var checkboxName = $(this).val();
$('.callout').each(function() {
var calloutArray = $(this).data();
$(this).toggle(calloutArray.category.indexOf(checkboxName) != -1);
});
}
});
});
Also note that
if ($(this).prop('checked') === true) {
is quite a long way to write
if (this.checked) {
Similarly, with inputelements, this.value is the same as $(this).val().
I have a form spread across multiple divs that are being displayed on and off using jQuery. I would like to disable the next and previous buttons on the first and last div when they are visible.
This sounded like an easy task based on the little that I do know about jQuery but it is proving to be more difficult than I imagined given my current code.
Here are my current next and previous button functions
var sel = "div[data-type='form']";
var current = $(sel).get(0);
$(sel).not(current).hide();
$("#next").click(function () {
if ($(form).valid()) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
});
and here is a fiddle of what is happening at the moment http://jsfiddle.net/GZ9H8/6/
This works (Note: I removed the validation for testing purposes).
$("#next").click(function () {
if (true) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
if (!$(current).next(sel).get(0)){
$(this).hide();
}
if ($(current).prev(sel).get(0)){
$("#prev").show();
}
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
if ($(current).next(sel).get(0)){
$("#next").show();
}
if (!$(current).prev(sel).get(0)){
$(this).hide();
}
});
Note that the previous button should probably be hidden from the start. Also, you can disable instead of hide if you want.
This may be useful:
$("#next").click(function () {
if ($(form).valid()) {
current = $(current).next(sel);
$(current).show();
$(sel).not(current).hide();
// Last element's index is equal to length - 1
$(this).attr('disabled', current.index(sel) == $(sel).length - 1);
// First element's index is equal to 0
$("#prev").attr('disabled', current.index(sel) == 0);
}
});
$("#prev").click(function () {
current = $(current).prev(sel);
$(current).show();
$(sel).not(current).hide();
// Last element's index is equal to length - 1
$("#next").attr('disabled', current.index(sel) == $(sel).length - 1);
// First element's index is equal to 0
$(this).attr('disabled', current.index(sel) == 0);
});
Regards
I have the following snippets of code. Basically what I'm trying to do is in the 1st click function I loop through my cached JSON data and display any values that exist for that id. In the 2nd change function I capturing whenever one of the elements changes values (i.e. yes to no and vice versa).
These elements are all generated dynamically though the JSON data I'm receiving from a webservice. From my understanding that is why I have to use the .live functionality.
In Firefox everything works as expected (of course). However, in IE7 it does not. In IE7, if I select a radio button that displays an alert from the click function then it also adds to the array for the changed function. However, if the radio button does not do anything from the click function then the array is not added to for the change.
As I look at this code I'm thinking that I might be able to combine these 2 functions together however, right now I just want it to work in IE7.
$(document).ready(function () {
//This function is run whenever a 'radio button' is selected.
//It then goes into the CPItemMetaInfoList in the cached JSON data
//($.myglobals) and checks to see if there are currently any
//scripts to display.
$("input:radio").live("click", function () {
var index = parseInt(this.name.split(':')[0]);
for (i = 0; i <= $.myglobals.result.length - 1; i++) {
if ($.myglobals.result[i].CPItemMetaInfoList.length > 0) {
for (j = 0; j <= $.myglobals.result[i].CPItemMetaInfoList.length - 1; j++) {
if (index == $.myglobals.result[i].QuestionId) {
alert($.myglobals.result[i].CPItemMetaInfoList[j].KeyStringValue);
return;
}
}
}
}
});
});
$(document).ready(function () {
var blnCheck = false;
//Checks to see if values have changed.
//If a value has been changed then the isDirty array gets populated.
//This array is used when the questionSubmit button is clickeds
$('input').live('change', function () {
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
alert($(this).attr("name"));
}
});
$('textarea').live('change', function () {
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("id")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("id");
arrayCount += 1;
//alert($(this).attr("name"));
}
});
});
UPDATE:
I had to move this chunk of code into the click function:
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
alert($(this).attr("name"));
}
Like this:
$(document).ready(function () {
//This function is run whenever a 'radio button' is selected.
//It then goes into the CPItemMetaInfoList in the cached JSON data
//($.myglobals) and checks to see if there are currently any
//scripts to display.
$("input:radio").live("click", function () {
var index = parseInt(this.name.split(':')[0]);
for (i = 0; i <= $.myglobals.result.length - 1; i++) {
if ($.myglobals.result[i].CPItemMetaInfoList.length > 0) {
for (j = 0; j <= $.myglobals.result[i].CPItemMetaInfoList.length - 1; j++) {
if (index == $.myglobals.result[i].QuestionId) {
alert($.myglobals.result[i].CPItemMetaInfoList[j].KeyStringValue);
return;
}
}
}
}
blnCheck = false;
for (i = 0; i <= isDirty.length - 1; i++) {
if (isDirty[i] == $(this).attr("name")) {
blnCheck = true;
break
}
}
if (blnCheck == false) {
isDirty[arrayCount] = $(this).attr("name");
arrayCount += 1;
}
});
});
But...
I had to leave the change function the same. From my testing I found that the .click function worked for IE7 for the radio buttons and checkbox elements, but the .change functionality worked for the textboxes and textareas in IE7 and FF as well as the original functionality of the radio buttons and checkbox elements.
This one got real messy. Thanks to #Patricia for looking at it. Here suggestions did lead me to this solution. I'm going to leave the question unanswered as I wonder if there isn't a cleaner solution to this.
Fact: change event on radio buttons and checkboxes only get fired when the focus is lost (i.e. when the blur event is about to occur). To achieve the "expected" behaviour, you really want to hook on the click event instead.
You basically want to change
$('input').live('change', function() {
// Code.
});
to
$('input:radio').live('click', functionName);
$('input:not(:radio)').live('change', functionName);
function functionName() {
// Code.
}
(I'd however also take checkboxes into account using :checkbox selector for the case that you have any in your form, you'd like to treat them equally as radiobuttons)
I think this is because IE fires the change when focus is lost on checks and radios. so if the alert is popping up, focus is being lost and therefor the change event is firing.
EDIT:
try changing the $('input') selector to $('input:not(:radio)')
so the click will fire for your radios and the change for all your others.
Edit #2:
How bout putting the stuff that happens on change into a separate function. with the index as a parameter. then you can call that function from the change() and the click(). put the call to that function after your done with the click stuff.
You're declaring your blnCheck variable inside one of your document.ready() functions. You don't need two of these either, it could all be in one.
This means that the variable that you're declaring there won't be the one used when your change function is actually called, instead you're going to get some kind of implicit global. Don't know if this is part of it, but might be worth looking at. You should declare this at the top of your JS file instead.