So I took this code from this website. I don't want to have all the fields being required. Like, let's say, full middle name. I want that field to be optional (hence, not affecting the function for checking which fields have error). How can I do it?
$(function() {
/*
number of fieldsets
*/
var fieldsetCount = $('#formElem').children().length;
/*
current position of fieldset / navigation link
*/
var current = 1;
/*
sum and save the widths of each one of the fieldsets
set the final sum as the total width of the steps element
*/
var stepsWidth = 0;
var widths = new Array();
$('#steps .step').each(function(i){
var $step = $(this);
widths[i] = stepsWidth;
stepsWidth += $step.width();
});
$('#steps').width(stepsWidth);
/*
to avoid problems in IE, focus the first input of the form
*/
$('#formElem').children(':first').find(':input:first').focus();
/*
show the navigation bar
*/
$('#navigation').show();
/*
when clicking on a navigation link
the form slides to the corresponding fieldset
*/
$('#navigation a').bind('click',function(e){
var $this = $(this);
var prev = current;
$this.closest('ul').find('li').removeClass('selected');
$this.parent().addClass('selected');
/*
we store the position of the link
in the current variable
*/
current = $this.parent().index() + 1;
/*
animate / slide to the next or to the corresponding
fieldset. The order of the links in the navigation
is the order of the fieldsets.
Also, after sliding, we trigger the focus on the first
input element of the new fieldset
If we clicked on the last link (confirmation), then we validate
all the fieldsets, otherwise we validate the previous one
before the form slided
*/
$('#steps').stop().animate({
marginLeft: '-' + widths[current-1] + 'px'
},500,function(){
if(current == fieldsetCount)
validateSteps();
else
validateStep(prev);
$('#formElem').children(':nth-child('+ parseInt(current) +')').find(':input:first').focus();
});
e.preventDefault();
});
/*
clicking on the tab (on the last input of each fieldset), makes the form
slide to the next step
*/
$('#formElem > fieldset').each(function(){
var $fieldset = $(this);
$fieldset.children(':last').find(':input').keydown(function(e){
if (e.which == 9){
$('#navigation li:nth-child(' + (parseInt(current)+1) + ') a').click();
/* force the blur for validation */
$(this).blur();
e.preventDefault();
}
});
});
/*
validates errors on all the fieldsets
records if the Form has errors in $('#formElem').data()
*/
function validateSteps(){
var FormErrors = false;
for(var i = 1; i < fieldsetCount; ++i){
var error = validateStep(i);
if(error == -1)
FormErrors = true;
}
$('#formElem').data('errors',FormErrors);
}
/*
validates one fieldset
and returns -1 if errors found, or 1 if not
*/
function validateSteps(){
var FormErrors = false;
for(var i = 1; i < fieldsetCount; ++i){
var error = validateStep(i);
if(error == -1)
FormErrors = true;
}
$('#formElem').data('errors',FormErrors);
}
/*
validates one fieldset
and returns -1 if errors found, or 1 if not
*/
function validateStep(step){
if(step == fieldsetCount) return;
var error = 1;
var hasError = false;
$('#formElem').children(':nth-child('+ parseInt(step) +')').find(':input:not(button)').each(function(){
var $this = $(this);
var valueLength = jQuery.trim($this.val()).length;
if(valueLength == '')
{
hasError = true;
$this.css('background-color','red');
}
else
{
$this.css('background-color','yellow');
}
}
);
var $link = $('#navigation li:nth-child(' + parseInt(step) + ') a');
$link.parent().find('.error,.checked').remove();
var valclass = 'checked';
if(hasError)
{
error = -1;
valclass = 'error';
}
$('<span class="'+valclass+'"></span>').insertAfter($link);
return error;
}
/*
if there are errors don't allow the user to submit
*/
$('#registerButton').bind('click',function(){
if($('#formElem').data('errors')){
alert('Please correct the errors in the Form');
return false;
}
});
});
inside validateStep function on line where you perform the find just add this tag after :input like below:
$('#formElem').children(':nth-child('+ parseInt(step)+')').find(':input[required]:not(button)')
You just have to use the required html attribute inside your web page and when you will run the validateStep function, it will ignore all fields without the required attribute.
look at mdn doc for more informations.
https://developer.mozilla.org/en-US/docs/Web/CSS/:required
Related
I have this snippet found below which highlights and jumps to the searched term. The current snippet searches after each keystroke that the user inputs which is putting too much stress on the server. Instead I want it to mark and jump once the user presses enter or clicks the next button. I've tried change the following line but it's breaking the code. Any ideas?
$input.on("input", function() {
to
$nextBtn.on('click', function() {
Code here:
$(function() {
// the input field
var $input = $("input[type='search']"),
// clear button
$clearBtn = $("button[data-search='clear']"),
// prev button
$prevBtn = $("button[data-search='prev']"),
// next button
$nextBtn = $("button[data-search='next']"),
// the context where to search
$content = $(".content"),
// jQuery object to save <mark> elements
$results,
// the class that will be appended to the current
// focused element
currentClass = "current",
// top offset for the jump (the search bar)
offsetTop = 50,
// the current index of the focused element
currentIndex = 0;
/**
* Jumps to the element matching the currentIndex
*/
function jumpTo() {
if ($results.length) {
var position,
$current = $results.eq(currentIndex);
$results.removeClass(currentClass);
if ($current.length) {
$current.addClass(currentClass);
position = $current.offset().top - offsetTop;
window.scrollTo(0, position);
}
}
}
/**
* Searches for the entered keyword in the
* specified context on input
*/
$input.on("input", function() {
var searchVal = this.value;
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
jumpTo();
}
});
}
});
});
/**
* Clears the search
*/
$clearBtn.on("click", function() {
$content.unmark();
$input.val("").focus();
});
/**
* Next and previous search jump to
*/
$nextBtn.add($prevBtn).on("click", function() {
if ($results.length) {
currentIndex += $(this).is($prevBtn) ? -1 : 1;
if (currentIndex < 0) {
currentIndex = $results.length - 1;
}
if (currentIndex > $results.length - 1) {
currentIndex = 0;
}
jumpTo();
}
});
});
Working JSFiddle found here: https://jsfiddle.net/83nbm2rv/
You can change the $input.on('input') to:
$input.on("keypress", function(e) {
if (e.which === 13) {
var searchVal = this.value;
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
jumpTo();
}
});
}
});
}
});
And that will handle pressing enter in the textbox. See this fiddle for the next button click update: https://jsfiddle.net/9g4xr765/
Basic approach was to functionalize the content marking and calling it on $input keypress, and also in next/previous click if there are no results.
There are still issues though, like if the value changes you can't use the next/previous button to search so that would require some additional work.
I'm trying to implement mark.js on a page, but it isn't working correctly. So I setup a very basic page, and pulled all of the code from this jsfiddle page, however it will only highlight certain 1-3 letters at a time, depending on whatever I put in. Can anyone see what I'm doing wrong exactly? My page is located here.
Code:
$(function() {
// the input field
var $input = $("input[type='search']"),
// clear button
$clearBtn = $("button[data-search='clear']"),
// prev button
$prevBtn = $("button[data-search='prev']"),
// next button
$nextBtn = $("button[data-search='next']"),
// the context where to search
$content = $(".content"),
// jQuery object to save <mark> elements
$results,
// the class that will be appended to the current
// focused element
currentClass = "current",
// top offset for the jump (the search bar)
offsetTop = 50,
// the current index of the focused element
currentIndex = 0;
/**
* Jumps to the element matching the currentIndex
*/
function jumpTo() {
if ($results.length) {
var position,
$current = $results.eq(currentIndex);
$results.removeClass(currentClass);
if ($current.length) {
$current.addClass(currentClass);
position = $current.offset().top - offsetTop;
window.scrollTo(0, position);
}
}
}
/**
* Searches for the entered keyword in the
* specified context on input
*/
$input.on("input", function() {
var searchVal = this.value;
$content.unmark({
done: function() {
$content.mark(searchVal, {
separateWordSearch: true,
done: function() {
$results = $content.find("mark");
currentIndex = 0;
jumpTo();
}
});
}
});
});
/**
* Clears the search
*/
$clearBtn.on("click", function() {
$content.unmark();
$input.val("").focus();
});
/**
* Next and previous search jump to
*/
$nextBtn.add($prevBtn).on("click", function() {
if ($results.length) {
currentIndex += $(this).is($prevBtn) ? -1 : 1;
if (currentIndex < 0) {
currentIndex = $results.length - 1;
}
if (currentIndex > $results.length - 1) {
currentIndex = 0;
}
jumpTo();
}
});
});
This ended up being an encoding issue. Adding:
<meta charset="UTF-8">
resolved the problem.
I have two lists of divs that I wish to navigate through with buttons (up, down, left, right). Each time a button is pressed, the result div in my html gets replaced with the "current" div. As such, I have a horizontal and vertical list. The horizontal navigation works perfectly but when I click my down button, my vertical list returns an index of -1 and nothing is displayed. Here is my code:
$(document).ready(function(){
//this creates the lists of divs
var $list = $(".slides > div");
var $vlist = $(".yslides > div");
//this initializes the index tracking values horizontal
//and vertical
var $hcurrent = 0;
var $vcurrent = 0;
//this is because I kept getting console undefined errors
if (typeof console == "undefined") {
window.console = {
log: function () {}
};
}
/*
R I G H T B U T T O N
*/
$("#right").click(function(){
//this removes the current indexed div
//and sets the the current index as next
var $next = $list.filter(".current").removeClass('current').next();
//this is for wrap around
//if this hits the max value of horizontal indexes it wraps around
if(!$next.length){
$next = $list.first()
}
//this adds the next div
$next.addClass('current');
//this outputs the div to the "result" div
$("#result").html('').append($next.clone());
//this tracks and updates the horizontal index
$hcurrent = $list.index($(".current"));
//this is for the undefined error, again
if (typeof console == "undefined") {
window.console = {
log: function () {}
};
}
//this is the console out put, tracks the current horizontal index,
horizontal list length(number of indexes, active flag
//current veritical idex, and vertical list length
console.log("Right Pressed. " , "hc: ",$hcurrent, "hi: ",$list.length,
$active, "vc: ", $vcurrent,"vi: ",$vlist.length);
});
/*
L E F T B U T T O N
*/
$("#left").click(function(){
//this removes the current indexed div
//and sets the the current index as the Previous element
var $next = $list.filter(".current").removeClass('current').prev();
//this adds the previous class to $next
$next.addClass('current');
//this appends the previous index/class to result
$("#result").html('').append($next.clone());
//tracks current horizontal index
$hcurrent = $list.index($(".current"));
//active flag controls
if (($hcurrent != 0) && ($hcurrent % 2 == 0) ){
$active = true;
}
else{
$active = false;
}
//undefined console error checking
if (typeof console == "undefined") {
window.console = {
log: function () {}
};
}
console.log("Left Pressed. " , "hc: ",$hcurrent, "hi: ",$list.length, $active, "vc: ", $vcurrent,"vi: ",$vlist.length);
});
/*
D O W N B U T T O N
*/
$("#down").click(function(){
//this removes the current indexed div
//and sets the the current index as the Previous element
var $next = $vlist.filter(".current").removeClass('current').next();
//this adds the previous class to $next
$next.addClass('current');
alert("added the class");
//this appends the previous index/class to result
$("#result").html('').append($next.clone());
//tracks current horizontal index
$hcurrent = $list.index($(".current"));
//active flag controls
if (($hcurrent != 0) && ($hcurrent % 2 == 0) ){
$active = true;
}
else{
$active = false;
}
//undefined console error checking
if (typeof console == "undefined") {
window.console = {
log: function () {}
};
}
console.log("Left Pressed. " , "hc: ",$hcurrent, "hi: ",$list.length, $active, "vc: ", $vcurrent,"vi: ",$vlist.length);
});
});
Here is my JSFiddle : DEMO
On click of "Save & Continue", the step navigates to the next step of the wizard.
How do I navigate to any step on click of a specific step? (instead of the step-by-step sequence that already exists)
$('.f1 .btn-next').on('click', function() {
var parent_fieldset = $(this).parents('fieldset');
var next_step = true;
// navigation steps / progress steps
var current_active_step = $(this).parents('.f1').find('.f1-step.active');
var progress_line = $(this).parents('.f1').find('.f1-progress-line');
// fields validation
parent_fieldset.find('input[type="text"], input[type="password"], textarea').each(function() {
if( $(this).val() == "" ) {
$(this).addClass('input-error');
next_step = true;
}
else {
$(this).removeClass('input-error');
}
});
Edit:- Buttons added to jump to specific steps. Fiddle
EDIT:- I modified your fiddle check this
Try this JsFiddle demo
I modified the html slightly to connect steps div and corresponding fieldset by adding a data-step parameter to both. After the modification the below function will allow you to jump between steps by clicking on the icon.
$(this).parents('.f1').find('.f1-progress-line');
fieldsetToActivate = $(this).data('step');
let direction;
if (current_active_step.data('step') > fieldsetToActivate) {
direction = 'left';
} else {
direction = 'right';
}
$("form.f1 fieldset").hide();
current_active_step.removeClass('active');
// bar_progress(progress_line, direction);
// ************* //
var number_of_steps = progress_line.data('number-of-steps');
var now_value = progress_line.data('now-value');
var new_value = 0;
if (direction == 'right') {
new_value = fieldsetToActivate * (100 / number_of_steps);
} else if (direction == 'left') {
new_value = fieldsetToActivate * (100 / number_of_steps);
}
console.log('now:' + now_value + '- new: ' + new_value);
progress_line.attr('style', 'width: ' + new_value + '%;').data('now-value', new_value);
// ****************** //
$('.f1').find(`fieldset[data-step='${fieldsetToActivate}']`).fadeIn('slow');
// change icons
$('.f1-step').removeClass('activated');
$(this).addClass('active');
for (let j = 0; j < fieldsetToActivate; j++) {
$('.f1').find(`.f1-step[data-step='${j}']`).addClass('activated');
}
});
This is not the best solution, but this will get your job done
I created this site where you have multiple sliders moving vertically using this example on stackoverflow > here < along with this fiddle.
The site when loaded has an overflow: hidden on the body and position fixed on my main content div(div class="content-fs row"). The idea is that when you first arrive on the page, you scroll through each slide and once you hit the last one, the position changes on the main content div(div class="content-fs row") from fixed to static and the overflow: hidden is removed from the body. I'm having trouble writing the conditional statement that says "if its the last slider, change the position." The jquery below is the code i'm using for the site along with the conditional statement that doesn't work.
Any pointers/advice would be greatly appreciated!
jquery:
function scrollLax(){
/*
initialize
*/
var scrollDown = false;
var scrollUp = false;
var scroll = 0;
var $view = $('#portfolio');
var t = 0;
var h = $view.height() - 250;
$view.find('.portfolio-sliders').each(function() {
var $moving = $(this);
// position the next moving correctly
if($moving.hasClass('from-bottom')) {
$moving.css('top', h); // subtract t so that a portion of the other slider is showing
}
// make sure moving is visible
$moving.css('z-index', 10);
});
var $moving = $view.find('.portfolio-sliders:first-child');
$moving.css('z-index', 10);
/*
event handlers
*/
var mousew = function(e) {
var d = 0;
if(!e) e = event;
if (e.wheelDelta) {
d = -e.wheelDelta/3;
} else if (e.detail) {
d = e.detail/120;
}
parallaxScroll(d);
}
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', mousew, false);
}
window.onmousewheel = document.onmousewheel = mousew;
/*
parallax loop display loop
*/
window.setInterval(function() {
if(scrollDown)
parallaxScroll(4);
else if(scrollUp)
parallaxScroll(-4);
}, 50);
function parallaxScroll(scroll) {
// current moving object
var ml = $moving.position().left;
var mt = $moving.position().top;
var mw = $moving.width();
var mh = $moving.height();
// calc velocity
var fromBottom = false;
var vLeft = 0;
var vTop = 0;
if($moving.hasClass('from-bottom')) {
vTop = -scroll;
fromBottom = true;
}
// calc new position
var newLeft = ml + vLeft;
var newTop = mt + vTop;
// check bounds
var finished = false;
if(fromBottom && (newTop < t || newTop > h)) {
finished = true;
newTop = (scroll > 0 ? t : t + h);
}
// set new position
$moving.css('left', newLeft);
$moving.css('top', newTop);
// if finished change moving object
if(finished) {
// get the next moving
if(scroll > 0) {
$moving = $moving.next('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:last');
//this is where I am trying to add the if conditional statement.
if ('.portfolio-sliders:last')
$('.content-fs.row').css({'position': 'static'});
if('.portfolio-sliders:last' && (mt == 0))
$('html, body').removeClass('overflow');
} else {
$moving = $moving.prev('.portfolio-sliders');
if($moving.length == 0)
$moving = $view.find('.portfolio-sliders:first-child');
//reverse the logic and if last slide change position
if('.portfolio-sliders:first-child')
$('.content-fs.row').css({'position': 'fixed'});
}
}
// for debug
//$('#direction').text(scroll + "/" + t + " " + ml + "/" + mt + " " + finished + " " + $moving.text());
}
}
Your code as it is simply asks whether .portfolio-sliders:last exists. Seems you should be doing:
if ($moving == $('.portfolio-sliders:last') )
or something along those lines, instead checking whether the active slide is the last.