I'm writing a 100% JavaScript webapp that manages a catalog of products.
I'm using Backbone & Mustache, among other things.
Each product has a name, which needs to be translated. So for each product, I add as many <input> elements as there are languages to translate, something like this :
<input type="text" name="name_fr" value="Bonjour" class="i18n lang_fr">
<input type="text" name="name_en" value="Hello" class="i18n lang_en">
<input type="text" name="name_es" value="Hola" class="i18n lang_es">
I show/hide <input> elements depending on the currently selected language relying on CSS classes, on the first rendering and also when the user changes the language :
var $html = ...; // Render Mustache template
var cssClass = 'lang_' + currentLanguageId;
$html.find('.i18n.' + cssClass).show();
$html.find('.i18n:not(.' + cssClass + ')').hide();
This method is a maybe a little bit naïve, but it is simple, because each input field contains all the necessary information in its attributes to save the data. I'm listening the blur event to save data when the user leaves the field.
The problem is that the language switch is slow when the number of elements grows.
Am I using the good technique ? I don't think re-rendering the product items when the language changes would be a good solution.
Can't you use css instead of javascript to toggle the show/hide?
E.g.:
.lang_fr,.lang_en,.lang_es {display:none}
.fr .lang_fr {display:inline}
.en .lang_en {display:inline}
.es .lang_es {display:inline}
...
<div class="fr">
<input type="text" name="name_fr" value="Bonjour" class="i18n lang_fr">
<input type="text" name="name_en" value="Hello" class="i18n lang_en">
<input type="text" name="name_es" value="Hola" class="i18n lang_es">
</div>
Then just toggle the fr class of the outer div.
Related
I have a user account page where I would like users to see a very basic form with the details of their account and, on page load, I would like this form to be in a read-only state. If users want to edit their account details, they can click on an edit button which will dynamically remove the readonly state of all of the input fields.
I have the following:
<button
type="button"
aria-pressed="false"
aria-controls="EditAccount"
>
Edit Account Details
</button>
<form id="EditAccount" class="profile-form">
<label for="first_name">First name</label>
<input type="text" name="first_name" id="first_name" value="Maria" readonly>
<label for="last_name">Last name</label>
<input type="text" name="last_name" id="last_name" value="Juana" readonly>
<button type="submit" hidden>Submit</button>
</form>
Would using the aria-controls attribute on the button be enough to let users that use assistive technologies know that the button is toggling the readonly state of the entire form?
I've found similar questions on Stack Overflow on how to toggle the readonly state of an entire form but none that address my accessibility concerns.
Would I need to use a different approach to make it clear to these users that the form is toggling between an editable and readonly state?
No, aria-controls is not what you want. While there are many ARIA attributes that allow toggling the value, and the toggling is announced by screen readers, there isn't one specifically for changing the readonly attribute.
Yes, there is an aria-readonly that you could potentially toggle but it's a property attribute and not a state attribute. It's a fine distinction but in general, state attributes, such as aria-checked or aria-expanded, are expected to change/toggle, usually based on user interaction, and thus their state change is automatically announced by the screen reader without you having to do any extra coding (other than actually changing the value of the attribute).
Property attributes are generally set once and don't change so the screen reader will not announce changes to these attributes. For example, aria-label or aria-multiline or aria-readonly. There's nothing that prevents you from changing the value of these attributes, and it's perfectly valid to do so, but the change will not be announced.
In your case, it doesn't sound like you're changing the value of any ARIA attributes. You're using the built in readonly attribute on the <input>, right?
When the user makes the change, do you visually notify the user that all the fields are editable now? Or do you rely on the appearance of the input field changing from readonly to editable to be the indicator?
If you display a visible text message that says something like "all fields are editable now", then you can make that text message an aria-live region. If you don't display a message like that, then you can create a visibly hidden message just for screen reader users. From a UX perspective, it'd be better for everyone to know about the change, but without seeing your application, perhaps you're already notifying the users in some way.
Assuming you have a text message that you display to users, then you could have something like this:
<div aria-live="polite">
</div>
Then when you inject text into the container, it'll automatically be announced by screen readers.
<div aria-live="polite">
all fields are editable now
</div>
If you don't want that message to be visible, you can use a "sr-only" type class. There's nothing special about the name of that class. It's just a common name to use. See What is sr-only in Bootstrap 3?
<div aria-live="polite" class="sr-only">
</div>
Django formsets have an empty_form attribute.
empty_form
BaseFormSet provides an additional attribute empty_form
which returns a form instance with a prefix of __prefix__ for easier
use in dynamic forms with JavaScript.
The Django documentation doesn't actually say how to replace the __prefix__ with Javascript. Several online examples show how to do it with jQuery, but I specifically want to do it with Javascript - no jQuery.
Here is the resulting HTML from my {{ formset.empty_form }}:
<div id="prerequisiteEmptyForm">
<input type="text" name="prerequisites-__prefix__-text" maxlength="100" id="id-prerequisites-__prefix__-text">
<label for="id-prerequisites-__prefix__-DELETE">Delete:</label>
<input type="checkbox" name="prerequisites-__prefix__-DELETE" id="id-prerequisites-__prefix__-DELETE">
<input type="hidden" name="prerequisites-__prefix__-id" id="id-prerequisites-__prefix__-id">
<input type="hidden" name="prerequisites-__prefix__-content" value="21" id="id-prerequisites-__prefix__-content">
</div>
Everywhere it shows __prefix__, I want to replace it with a number... let's say 321.
Correct solution:
<div id="prerequisiteEmptyForm">
<input type="text" name="prerequisites-321-text" maxlength="100" id="id-prerequisites-321-text">
<label for="id-prerequisites-321-DELETE">Delete:</label>
<input type="checkbox" name="prerequisites-321-DELETE" id="id-prerequisites-321-DELETE">
<input type="hidden" name="prerequisites-321-id" id="id-prerequisites-321-id">
<input type="hidden" name="prerequisites-321-content" value="21" id="id-prerequisites-321-content">
</div>
So my question becomes
Using Javascript only, how do I replace a constant value ("__prefix__") with something else ("321") across several elements (inputs and labels) within multiple attributes (name, id)? Specifically, I want to do it cleanly for repeatability. I don't want a highly custom solution to this specific problem. It needs to be a general approach... since this is replacing a constant, surely Javascript has a clean way to do this? I'm still learning Javascript and trying to not be so dependent on jQuery.
I used this concept:
const emptyForm = document.querySelector('#prerequisiteEmptyForm');
clone = emptyForm.cloneNode(deep=true);
clone.innerHTML = clone.innerHTML.replace(/__prefix__/g, '321');
i am loading handlebar templates in the two div locations(like add and edit tabs both are jsps) from the same page. so i have duplicate elements in the DOM object, since it is a template which is coming from server location. you can see the sample code below
<div id="add">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
<div id="edit">
<div id="exploding">
<input type="text" name="city" id="city"/>
<input type="text" name="state" id="state"/>
...
</div>
</div>
I can't modify the div container ids i.e exploding since some javascript functions attached to it based on that id to explode address field.
here the problem is if i made any changes to the edit tab, address "exploding" div, it is effecting in add tab address "exploding" since ids are repeated. i have tried jquery detach method to remove the dom elements, but didn't get proper result. Its a web application based on spring boot.
is there any possibility to load jsps dynamically through jquery, i have tried load method as well, but the call is going through controller. I didn't feel it as better option.
Thanks & Regards
krishna K
I often use classes as a means to identify a related set of elements, for example:
<input value="10" class="sum-this" />
<input value="20" class="sum-this" />
<input value="30" class="sum-this" />
The sum-this class has no CSS, and isn't defined in any CSS files -it's simply used in some jQuery - for example:
var total = 0;
$(".sum-this").each(function(i, el){
total += parseInt($(el).val());
});
console.log(total); // 60?
Is there a correct way to do this? Should I use another attribute? rel or data-*?
As #Pointy and #JustinPowell have stated in the comments, this is completely valid. In fact, it's also explicitely stated in the W3C HTML4 specification that using class attributes for purposes other than selecting style is completely valid. I quote:
The class attribute, on the other hand, assigns one or more class names to an element; the element may be said to belong to these classes. A class name may be shared by several element instances. The class attribute has several roles in HTML:
As a style sheet selector (when an author wishes to assign style information to a set of elements).
For general purpose processing by user agents.
However, HTML5 also added the custom data-* attributes (where * is a custom string) for this purpose.
LINKS
A blog post discussing your question
W3C HTML4 attributes
W3C HTML 5 data attribute
As said in the comments, it's perfectly fine to use classes in the JavaScript only. But here's a suggestion: when my colleagues want to use a class for this purpose only, they prefix it by 'js-' in order to distinguish classes used for styling from classes made for JS.
While your code is syntactically valid using classes and there's nothing wrong with it, since you're looking for something that's semantically correct I'd recommend data attributes. Classes are really meant to be used for styling while data attribtes were created "with extensibility in mind for data that should be associated with a particular element but need not have any defined meaning. "
You could write your HTML like:
<input value="10" data-item="sum-this" />
<input value="20" data-item="sum-this" />
<input value="30" data-item="sum-this" />
And your jQuery like:
var total = 0;
$('input[data-item="sum-this"]').each(function(i, el){
total += parseInt($(el).val());
});
console.log(total);
jQuery selector optimization is less important than it used to be, as more browsers implement getElementsByClassName, querySelector and querySelectorAll which parses CSS syntax.
So the burden of selection shifts from jQuery to the browser and now jQuery supports most CSS3 selectors, as well as some non-standard selectors and you can choose the selector you want to work with.
However, there are still some tips to keep in mind:
Use an ID if Possible
Avoid Selecting by Class Only
Avoid overly complex selectors
Increase Specificity from Left to Right
Avoid Selector Repetition
As everyone else has said, it's entirely appropriate to class elements for the purposes of javascript only.
In the example that you give, the alternative to collecting these elements:
<input value="10" class="sum-this" />
<input value="20" class="sum-this" />
<input value="30" class="sum-this" />
with:
document.querySelectorAll('.sum-this'); (or $('.sum-this') in jQuery)
might be to collect these elements:
<input value="10" />
<input value="20" />
<input value="30" />
with:
document.querySelectorAll('input[value]');
I currently have some third party client-side "magic widgets" library that I have to deal with... :) All I have to do really is to add some small amount of behavior to those things with jQuery to accommodate for some simple business rules. A lot of times, I find myself selecting a bunch of elements in the same way. Since "magic widgets" are already super heavy on JS, and I even notice it on my fast machine, I was trying to keep my own JS to an absolute minimum. So, given that the user clicks on one of the following inputs, what is the most efficient way to select all the inputs, including the clicked one, in the following structure with jQuery?
<div>
<label><input ... /></label>
<label><input ... /></label>
<label><input ... /></label>
</div>
First of all, your inputs shouldn't be wrapped in labels, but that's a different argument.
The fastest way is probably:
$('input').click(function(){
var siblings = $(this).closest('div').find('input');
});
This will select your clicked input again too, though. If that's a problem, try:
$('input').click(function(){
var siblings = $(this).closest('div').find('input').not($(this));
});
If you were using correct markup so that the label tags preceded each input element, then your HTML would look like
<div>
<label for="input1" /><input id="input1" ... />
<label for="input2" /><input ... />
<label for="input3" /><input ... />
</div>
Then your jQuery code becomes way easier:
$('input').click(function(){
var siblings = $(this).siblings('input');
});
Well, assuming none of the elements in that markup have unique id's or class names, the most efficient selector you can use is a combination of tag names and the >, or first-child selector:
$("div > label > input");
$("div>label>input") I presume. Although you could give each input a common class and do $("input.class").
it depends. if the markup only consists of your fragment than:
$('input');
All modern broswers have a cache to tags.
If your looking for the inputs in within the div add an id to the div:
<div id="input_fields">
<label><input ... /></label>
<label><input ... /></label>
<label><input ... /></label>
</div>
and use this selector:
$('#iput_fields > label > input');
The id is important since it is the fastest possible query a browser can perform.
Seems like using class name better than using tag names without any parent. Here is the test for it for test your self.
Maybe more complex html structure give different results.