I want to manage keyboard tab order functionality, I am using a template for header, footer and sidebar where many anchor element & input element exists. In template content we can not put and tabindex attribute which is not in my control.
Middle part of template is my work area, where I created a form and some element
<fieldset id="myWorkArea">
<div class="fieldrow">
<label for="input1">Class</label>
<input id="input1"/>
<a id="help1" href="#">what's this?</a>
</div>
<div class="fieldrow">
<label for="input2">Class</label>
<input id="input2"/>
<a id="help2" href="#">what's this?</a>
</div>
</fieldset>
In above code I want to cursor tabbing in below id order.
#help1 > #input1
#help2 > #input2
Is any approach to control keyboard tabbing order in only #myWorkArea fieldset elements as we can not put tabindex for all element in page?
Even if you have no access to the template, you can still add the tabindex attribute programmatically.
Here you have a snippet:
var tabindex = 1;
$('#myWorkArea .fieldrow').each( function() {
$('a', this).attr('tabindex', tabindex++);
$('input', this).attr('tabindex', tabindex++);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<fieldset id="myWorkArea">
<div class="fieldrow">
<label for="input1">Class</label>
<input id="input1"/>
<a id="help1" href="#">what's this?</a>
</div>
<div class="fieldrow">
<label for="input2">Class</label>
<input id="input2"/>
<a id="help2" href="#">what's this?</a>
</div>
</fieldset>
Hope it helps!
You can add the tab index programmatically using javascript as David mentioned in his answer.
Or If you want you can control the taborder functionality by binding your own event to only these elements like below code.
Working FIDDLE
$(function(){
var inputs = $('a#help1, a#help2,input#input1, input#input2');
$(inputs).bind('keydown', function (e) {
var self = $(this), form = self.parents('form:eq(0)'), focusable, next;
//check keycode for tabbing
if (e.keyCode == 9) {
switch($(this).attr("id")){
case "help1":
next=$('#input1');
break;
case "help2":
next=$('#input2');
break;
case "input1":
next=$('#help2');
break;
case "input2":
next=$('#help1');
break;
}
next.focus();
e.preventDefault();
return false;
}
});
});
Related
I have a sidebar on my page containing a form and some filters. The sidebar is initially collapsed and can be expanded when hovering over via a 'mouseenter' event, and will collapse when the mouse leaves the sidebar via a 'mouseover' event. This seems to work well, but I had an error when trying to add a input field in my form containing a datalist with a list of text options. The problem now is that when I hover over the options, the sidebar will trigger a 'mouseleave' event and collapse, even though the datalist/option elements are a child of the sidebar element. Is there a way to prevent the sidebar from collapsing or am I better off using select instead of datalist, since the select tag seems to not trigger 'mouseleave'?
let sidebar = document.getElementById("sidebar");
sidebar.addEventListener("mouseenter", function(e) {
toggleSidebar(e, BODY_CONTENT);
});
sidebar.addEventListener("mouseleave", function(e) {
toggleSidebar(e, BODY_CONTENT);
});
function toggleSidebar(e, bodyContent) {
if (e.type == "mouseenter") {
e.target.style.width = e.target.dataset.expandWidth + "px";
document.getElementById(bodyContent).style.marginLeft =
e.target.dataset.expandWidth + "px";
} else if (e.type == "mouseleave") {
console.log(e);
e.target.style.width = e.target.dataset.collapseWidth + "px";
document.getElementById(bodyContent).style.marginLeft =
parseInt(e.target.dataset.collapseWidth) + 10 + "px";
}
}
<div class="sidebar" id="sidebar" data-collapse-width="50" data-expand-width="300" style="width: 50px;">
<div id="flex-sidebar">
<div class="sidebar-header">
<h2>
Filters
</h2>
</div>
<form action="" method="POST" autocomplete="off">
<div class="form-group">
<label for="category-filter">Category:</label>
<input class="form-control me-2" type="search" placeholder="Filter Category" name="category-filter" value="" list="test">
<datalist class="sidebar-dropdown" id="test">
<option value="Option 1">1</option>
<option value="Option 2">2</option>
</datalist>
</div>
</form>
</div>
</div>
you should edit you snippet There a reference error,
and if you just want to toggle your sidebar like things, use data attribute and add a css class, something like this
nav[data-toggle='true']{ your styles when toggle==true }
and just switch data attribute using javascript
and also there a difference between mouseover and mouseenter you can find it on MDN.
Hope this helps!
I need to evaluate the contents of a hidden input field, who's value changes depending on the contents of an unordered list. For reference, this input field is part of a Tag-it! Single Input Field(2) assembly.
The problem with evaluating this sort of field is that onchange does not seem to fire on the input element, because the element is not in focus. That means I have two possible directions:
Figure out how to make the onchange event fire when the element isn't in focus;
Evaluate the contents of the unordered list.
The latter of these options seems the most appropriate, however it might also be heavy and possibly inaccurate. Which of these approaches should I be going for?
HTML:
<div id="Likes">
<div class="form-modal-back">
<div class="form-modal-title">
<h4>Choose some things you like</h4>
</div>
<div class="form-modal-main">
<h5>Start by typing a few letters, and choose from the suggestions</h5>
<div class="gap20"></div>
<div class="tagBox">
<input id="likesTags" name="tags" />
</div>
...
<a href="#Dislikes">
<input class="form-modal-button-right hiddenLink" id="onb5" type="button" value="Next" />
</a>
...
HTML at runtime:
<input id="likesTags" name="tags" class="tagit-hidden-field">
<ul class="tagit ui-widget ui-widget-content ui-corner-all">
<li class="tagit-new">
<input class="ui-widget-content ui-autocomplete-input" autocomplete="off" type="text">
<span role="status" aria-live="polite" class="ui-helper-hidden-accessible">1 result is available, use up and down arrow keys to navigate.</span>
</li>
</ul>
JS:
$("#likesTags").onchange(function () {
var text = $("#likesTags").val();
if (text.length > 2)
{
pageCompletionSequence += "1";
checkCompletion("#onb5", "#Dislikes", "11");
}
else
{
pageCompletionSequence = "1";
elementRestore("#onb5");
}
})
function checkCompletion(id, np, seq) {
if (pageCompletionSequence == seq) {
$(id).removeClass("hiddenLink");
$(id).parent().attr("href", np);
pageCompletionSequence = "1";
}
}
function elementRestore(id) {
$(id).addClass("hiddenLink");
$(id).parent().removeAttr("href");
}
This plugin has event callbacks for this case.
$("#likesTags").tagit({
//This should be appended to your current tagit initializing call.
afterTagAdded: function() {
onTagsUpdated('#likesTags');
},
afterTagRemoved: function() {
onTagsUpdated('#likesTags');
}
});
function onTagsUpdated(id){
var tags = $(id).tagit("assignedTags"); //Returns an array of the text values of all the tags currently in the widget.
console.log('tags of',id,'updated:',tags);
}
TL;DR:
I use $(..).append(node), but newly added nodes are not considered for inclusion despite them (supposedly) matching jQuery selectors.
Question
I have some code below that uses checkboxes but emulates radio button behavior. In other words, only one checkbox can (validly) be selected at any time. No more than one should be selected.
If you run the example below and click on the first 3 checkboxes, they will behave like radio buttons. Only one will be selected, no matter how many you click.
However, if you Add Point, newly added points will not be considered for the JS even though in theory it should grab them too...
Specifically: You can select the newly added checkbox, and it will be selected in addition to one already selected previously. That is incorrect as only 1 should be selected at any time and all others should be unselected.
What is happening and how can I have newly added nodes be included into jQuery selectors?
$(function() {
//check first box
$("input.duty:first").prop("checked", true);
//clicking unchecked box should check that box
//unchecks all others
$(".duty").on('click', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});
$("#addCasePoint").on("click", function() {
var newRowIndex = $('#newRowIndex').text();
var template = $('#casePointTemplate').data('template');
template = template.replace(/__index__/g, newRowIndex);
$('#casePointsFieldset').append(template);
$('#newRowIndex').text(++newRowIndex);
return false;
});
//deletes case point
$("#selection").on("click", ".removeCase", function() {
var caseCount = $('#selection .casePointFieldset').length
if (caseCount === 1) return false; //keep at least one row
$(this).closest("fieldset").remove();
return false;
});
});
.casePointFieldset {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="selection">
<fieldset id="casePointsFieldset">
<legend>Case Points</legend>
<div id="pointFieldset">
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
</div>
<!-- include template -->
<span id="casePointTemplate" data-template="<fieldset class="casePointFieldset"><div><label><span>Duty:</span> <input name="point[__index__]" class="duty" value="1" type="checkbox"></label></div><button class="removeCase">Remove</button></fieldset>">
</span>
</fieldset>
<button id="addCasePoint">Add Point</button>
</form>
The problem is how you're binding to them. The .click function (or .on('click')) basically works like this:
Find all of the currently existing elements which match a selector ($('.your.selector.here'))
Attach an event handler to each of those elements
Notice how I mentioned it binds to ones which already exist? That means it won't bind to newly created ones automatically. However, you can use .on to bind to the parent of those elements then listen for events on a selector. I'll show you what I mean:
$('#addItem').click(function() {
$('.container').append('<button class="item">Item</button>');
});
// Notice that I'm binding to the parent
// then specifying which events from it's children
// I want to listen to (click events from .item elements)
$('.container').on('click', '.item', function() {
console.log("I'm an item");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<button class="item">Item</button>
</div>
<button id="addItem">Add New Item</button>
If you change your on('click' to work like that then you'll have no problems.
Easiest way will be, attaching the event to the document. In the past this was done with the live() method.
$(document).on('click', '.duty', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});
I want to check if there is only one div with an error class. And if so, I want to .select() the content of the input (that's in the in corresponding input class div).
How would I do such thing?
My attempt which does not work:
if($("div.addition").hasClass(".error").length === 0) {
(this).parent().find('input').select();
}
HTML
<form>
<div class="input">
<input type="text">
<div>
<div class="addition">Message message.</div>
</div>
</div>
<div class="input">
<input type="text">
<div>
<div class="addition">Message.</div>
</div>
<div class="input">
<!-- So in this case this input's content will be selected -->
<input type="text">
<div>
<div class="addition error">Error message.</div>
</div>
</div>
</form>
Here's a jsFiddle that should do it - I mentioned as a comment to your post that you're missing a </div> tag, that is fixed in the fiddle - without it, the jquery selector matches two inputs. Outline of the js:
if ($('div.error').length === 1) {
errorContent = $('div.error').parents('div.input').find('input').val();
alert(errorContent);
}
Here's a plain JavaScript implementation. No need to use jQuery unless you're already using it.
var errors = document.getElementsByClassName('error');
if(errors.length === 1){
//If there is one class with error
var content = errors[0].innerHTML;
} else{
//there is more than one error class.
}
I want to check if there is only one div with an error class.
if ($("div.error").length === 1) {
// Exactly one div with the class "error"
}
else {
// Zero or more than one
}
By using jQuery it can be done like:
$(document).ready(function(){
var div = $('.error');
if(div.length){
var val = div.parents('.input:first').find('input').val();
//val is the value of input
}
});
I would like to show a form field textbox only when a certain checkbox is checked, and hide it when it is unhecked. I have gotten the code to make it hide when I check the box, but the textbox is displayed when the page is loaded until I check the box, which is opposite of what I would like to accomplish. I am pretty newbish with javascript so I am sure this is pretty elementary. Thanks for any help.
HTML:
<input type="checkbox" onclick="ShowCCFields(this.value);" name="CAT_Custom_510969" id="CAT_Custom_510969_7" value="Other..." />
Other...
<div class="item" id="other">
<label for="CAT_Custom_510972">Other:</label><br />
<textarea onkeydown="if(this.value.length>=4000)this.value=this.value.substring(0,3999);" class="cat_listbox" rows="4" cols="10" id="CAT_Custom_510972" name="CAT_Custom_510972"></textarea>
</div>
javascript:
// Hide or show textarea if the other checkbox field is checked
var voucher = document.getElementById("CAT_Custom_510969_7");
function ShowCCFields(val) {
if (!document.getElementById('other'))
return;
if (val == voucher.checked)
document.getElementById('other').style.display = 'inline';
else
document.getElementById('other').style.display = 'none';
}
Why not set the display to none to begin with? You can do that in CSS or just add it to
<div class="item" id="other" style="display: none;">
Set the style to none in the HTML, just like you do in the javascript:
<div class="item" id="other" style="display:none;">
Set Display to none in the control you want to hide :
<div class="item" id="other" style="display: none;">
And In your js Function :
document.getElementById('other').style.display = 'inline';