Element added to DOM but doesn't display on screen - javascript

Basically my problem is that when i add an element from the javascript (using jquery) the element that i added shows up in the web inspector but doesn't display in the browser at all.
What i am trying to do is simulate something i liked about google+ when it first came out, which is when you want to the user to enter a list of item, you provide them with one text field and once they start to add something to that text field then instantly after the first character is typed a new text field with appear under that. So I'm my code, i have the user entering a series of goals they want to achieve, i provide them with a single text field (or multiple if the user is editing the list they previously made) and once the last text field has data then it will programmatically create a new text field.
HTML:
<div class="field-group clickToAddGroup">
<label>Goals: </label>
<div class="input">
<input type="text" name="goals" value="Goal1">
<input type="text" name="goals" value="Goal2">
<input type="text" name="goals" value="Goal3">
<input type="text" name="goals" value="Goal4">
<input type="text" name="goals" placeholder="Type to add Goal" class="clickToAdd">
</div>
</div>
Javascript:
$(".clickToAdd").live('keyup',function(){
console.log("key up triggered");
if( $(this).val() != '' )
{
console.log("cloning in process");
var theClone = $(this).clone().val(''); // Set the new element to null
theClone.appendTo( $(this).parent() ); // Clone Parent
$(this).removeClass('clickToAdd'); // Remove the click to add class
console.log("clone complete");
}
console.log("key up finished");
console.log("----");
});
$('.clickToAddGroup input').live('blur', function(){
if( $(this).val() == '' && !$(this).hasClass('clickToAdd') )
$(this).remove();
});
Now the code above actually works, however when the page first loads when i click (or tab to) the last text field (one that has the clickToAdd class) and begin typing, i see in the web inspector that the javascript ran correctly and created the new field and placed it where it should, but i don't actually see it on the screen. But when i take the content that i had just wrote in the text field, delete it, and lose focus (triggering 'blur') the text field is deleted and then i can see the textfield that was shown. From this point on when i add content to the last field (one with the clickToAdd class) it works 100% perfectly, it adds the element and is visible via both the web inspector AND is displayed on screen.
Edit: I copied the code to jsfiddle (included css i am using as well) and tried it there and it happens to work perfectly as intended without the issue i am having. http://jsfiddle.net/qz2QK/2/
Edit 2: Added "var" to the line "var theClone = $(this).clone().val('');" so that its not implicitly a global variable.

Related

Focusing Element Prevents role="alert" Content From Being Announced

$(document).ready(function() {
$('#submitButton').click(function (){
$('#password').focus();
loadSRValidationMessages('#alertContainer', '.adhocError');
});
});
function loadSRValidationMessages(n, t) {
$(n).empty();
var content = "";
$(t).each(function() {
var t = $(this).text();
if (t.length > 0) {
content += "<p>" + t + "<\/p>";
}
})
$(n).append('<div id="alerts" role="alert" aria-atomic="true">' + content + '</div>');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div id="alertContainer">
</div>
<form id="loginForm">
<input type="password" id="password" required><br/>
<label class="adhocError">An example error.</label>
<button type="button" id="submitButton">Submit</button>
</form>
What I would like to present is an issue in which it seems as though focusing on an element interrupts, or perhaps prevents, the screen reader (NVDA) from announcing new role="alert" content. I have performed some research and looked at some existing Similar questions, though have yet to find a solution (ideally, having the screen reader announce new alert content as well as focusing on an element).
I have a simple scenario using jQuery. The code is abbreviated. Please let me know if you find any other information necessary.
Due to the way the role="alert" element works in some browser / screen reader combinations a more robust way is to add the full alert message and it's container to the page, rather than updating the text within the container.
If you need to issue multiple alerts you should just add multiple alert containers to the page (and ultimately remove the old alert containers, either via a close / dismiss button or when the alert is no longer relevant).
If you want to add multiple updates to a page, a better tactic is to place an aria-live="assertive" region onto the page and add / update content within that.
I find that the best way to handle updates for screen readers in a web application is to have a single aria-live="assertive" region on the page and have a central message queue in JavaScript (JS), with a delay between each message.
If you have something like a chat application or something that is not "urgent" that you don't want to interrupt a screen reader user with a second aria-live="polite" region can be added (using a second messages queue handled by JS).
That way you end up with two simple queues to add messages to messages.assertive and messages.polite and you will eliminate a load of problems associated with lots of aria-live regions (which include role="alert" regions).
I agree with Graham's view of the issue that if the focus event happens after the role="alert" is set, then the alert will be interrupted. Swap the order - first place focus on the invalid field, then set the role="alert".
Use both aria-invalid="true" on the invalid field, as well as link the specific error message to the field using aria-describedby, which will announce the error after the field label and value. (I wouldn't recommend aria-labelledby for linking the error message to the field as that attribute is used to program the field label, not the description, and you may end up confusing the user if you use aria-labelledby for the error message).
<div class="sr-only" id="errorList" role="alert" aria-atomic="true"></div>
<form id="frmlogin">
// Add aria-invalid, aria-labelledby, aria-describedby attributes to the field
<input type="text" id="name" aria-invalid="false" aria-labelledby="somelabel" aria-describedby="errorList"/>
<button id="submitButton">Submit</button>
</form>
<script>
$('#submitButton').click(function () {
if ($('#frmlogin').valid()) {
$('#frmlogin').submit();
}
else {
// Swap order of focus event and validation message so focus happens first
var validator = $("#frmlogin").validate();
validator.focusInvalid();
// Set the aria-invalid attribute to the field that has the error
$("#frmlogin").setAttribute("aria-invalid", "true");
// Load the validation messages
loadSRValidationMessages('#errorList', '.field-validation-error');
}
});
</script>

Why does setting the value of an input type file element using querySelecter work, but getElementById not?

Recently, I ran into a problem with an input type file element that stopped displaying the file selection dialog box, but didn't display any errors in the the debugger/code inspector. The element uses the jQuery wrap..reset..unwrap method to 'clear' the element. However, about six months ago this all worked fine in chrome, firefox, edge, and internet explorer, but now, nothing, so something has changed.
I copied the input type element and the click and change event handling code used to process the files selected with this element into a new web-page up on codepen to make it easier to demonstrate and work on. Sorry, it is rather lengthy, but the part that clears the input type file element just before causing the element to display the file selection dialog is right near the top of the javascript code at lines 9 and 10, so not hard to see.
<form id="fileImageForm" style="display: inline;">
<input type="button" id="button" value="Get pictures" />
<input type="text" id="text" style="width: 200px;" />
<input type="file" id="fileInput" class="file"
accept="image/jpeg, ... ,image/tiff" multiple
style="display: none;" />
<img id="fileImage" />
</form>
<script>
document.getElementById( 'button' )
.onclick = function() {
//
// Reset the input file element so the file selection
// dialog shows everytime the element is clicked ...
//
/* line 9 */ document.getDocumentById( 'fileInput' ) .value = '';
// Or
/* line 10 */ document.querySelector( '.file' ) .value = '';
// Click the input file element ...
document.getElementById( 'fileInput' ).click();
};
//
// When the user chooses one or more files with the input file element,
// the change event 'fires' and this function is called to validate and
// preview the selected image(s) ...
//
function fileInputChange( event ) { ... }
// Attach the change even to the input file element ...
document.getElementById( 'fileInput' )
.addEventListener( 'change', fileInputChange );
⫶
</script>
In any case here are two lines in question that I use in the new page to 'clear' the input type file element:
document.getDocumentById( 'fileInput' ) .value = '';
document.querySelector( '.file' ) .value = '';
Because I didn't want to work with jQuery in the codepen page, I went with the two most common javascript-only solutions that I could find.
While both of these use different methods to 'find' the input type file element, the 'clearing' is caused by directly assigning an empty string to the element's value. Both ways work fine in the codepen in all of the current versions of the major browsers and seem quite straight forward.
The often used jQuery wrap-reset-unwrap method that is not shown, does its 'work' by enclosing the input type file element in a temporary form element, calling the form's reset method to indirectly 'clear' the input element, and then removing the temporary form element, but as I said above, this means of clearing the input element stopped working for me in the current version of chrome, at least in my web-app, possibly because the event handlers assigned to the element are being corrupted by the form element wrapping and unwrapping each the the input element is clicked, possibly a memory issue, I don't know.
So, why if, since in the current version of all of the major browsers, the direct value assignment method of clearing the input element works, should I use the jQuery method, especially since I am experiencing issues with it until I fully debug it?
Thanks.

How do you control which field iOS/Android will focus to when you click next while you're filling out a form?

The scenario is that I have a modal with a multi-step process that I show one at a time, but not every step has a form field.
So when I'm ready to move on from Step 1 (which has a form field) and I click the next helper icon in the keyboard's toolbar (a function of iOS) it forwards me to an unavailable/translucent field in Step 4.
Step 1: Ask for age
Step 2: Choose a gender (these are LI elements)
Step 3: Choose interests (these are also LI elements)
Step 4: Enter a name
I've tried tabIndex, but that doesn't have any affect.
I'm not certain this is even possible since this is really an iOS control. If it's not possible can you hide that?
The undesirable fix would be to do a check when the user has focused on the Step 4 field and if the elements in Step 3 and Step 4 have not been chosen focus the user on the applicable previous step.
As far as I know,it's a same order of html structure.
So if you want to change the order, change html.
If you can't or You can't avoid the issue by changing the html file for some reason such as complicated html structure causing the issue or something.
Below code is how to disable <prev> <next> buttons of IOS keyboard.
html
<input type="text" />
<input type="number" />
<input type="date" />
<input type="time" />
<input type="tel" />
javascript(jquery)
$("input").on("touchstart",function(e){
_$activeElem = $(this);
//readonly disables next/prev buttons. so when user tap input field,turns any other input into readonly
//You cannot use focus here because keyboard shows up before focus fired,you need to use touchstart instead.
$("input").each(function(){
if($(this).get(0) === _$activeElem.get(0)){
_$activeElem.removeAttr("readonly");
$(this).one("blur",function(){
$(this).attr("readonly","readonly");
});
return;
}else{
$(this).attr("readonly","readonly");
}
});
//remove readonly property on blur
$("input").on("blur",function(){
if($("input:not([readonly])").length === -1){
$("input").removeAttr("readonly");
}
});
});
and make readonly input look like normal input field by CSS.

Rails javascript; alert to fire when leaving a field

My ultimate goal is to add some validation to a set of date fields. However, my javascript sucks, so I'm starting small.
I am starting out by trying to get an alert message when a user leaves a field.
(For simplicity I'm just doing it all in my view...) Heres what I go to work...
# html.erb-template
<div class="from_date">
From Date
<input type="text" id="from_date" name="from_date"></input>
</div>
<script>
$("#from_date").blur( function() {
alert("boom!");
});
</script>
Your code seems to be fine - problem is that class and id are named the same, but you want to watch the input field not the surrounding div.
I just made a fiddle from your script and changed
the listener to be attached to the input field's id - and it's working.
the alert into a console.log
see
$("#from_date").blur(function() {.....
// instead of
$(".from_date").blur(function() {.....

javascript code freezes the browser and the code only works in firefox

I have a form for which all text boxes should be filled before submission. my form looks like this
<form name="form" method="post" action="url" onsubmit="return checkEmpty(this)" >
<div class="field">
<label>field1</label><input type="text" name="f1" />
</div>
<div class="field">
<label>field2</label><input type="text" name="f2" />
</div>
..
....
......
input type="submit" name="Submit" value="submit" />
</form>
what i do here is that when a form is submitted i check if any text box is empty and if there is any i create a dom element h3 and append it to the div of that corresponding field and if the text box is not empty i check if there is any text box attached to that corresponding field and if i find one i remove it. here is my javascript code
function checkEmpty(form) {
var textboxes=form.elements;
for(var i=0;i<textboxes.length;i++)
{
if((textboxes[i].type=="text" || textboxes[i].type=="password") && textboxes[i].textLength==0) //text box is empty
{
var msg=document.createElement('h3');
msg.innerHTML="u cant leave this field blank";
textboxes[i].parentNode.appendChild(msg);
return false;
}
else //text box is not empty
{
var rem_msg=textboxes[i].parentNode.getElementsByTagName('h3');
for(var j=0;j<rem_msg.length;j++)
textboxes[i].parentNode.removeChild(rem_msg[j]);
}
}
}
Now the browser freezes when i submit the form.
*Also my code doesnt work in ggogle chrome but only firefox*
Until i was not removing elements the code was working fine but removing element is neccessary because say a user doesnt enter any value in text box 1 on first attempt so an h3 element would be added but now he enters some text in first text box but leaves second text box empty so the h3 element of first text box should dissappear.
because of the answer below the code
is no more freezing the browser but
still i am only able to add h3
elements to the dom but cannot remove
them.also the code works in firefox
but not in google chrome.
Problem is you are using the variable i in two distinct loops. When the inner loop finishes it will always end up setting i to rem_msg.length, which will keep the outer loop from ever reaching its exit condition so you end up with an infinite loop.
To fix your problem you simply need to rename the second i to e.g. j and you're good to go.
I think it may be the malformed for:
for(var i=0;i<rem_msg.length;;i++)
You have an extra ; so I think the i++ isn't getting run.

Categories