Which HTML/JS widget to display this balsamiq control? - javascript

I did mockups in balsamiq & they have this nice widget, which
Allowed to select a value, out of two values. Works really nicely on touchscreens
Can be used to Display two values & highlighting the selected one
Example:
What the options to implement a widget similar to shown in picture via HTML/CSS & JS?

The approach I present below iterates through all fieldset elements, and if all the inputs therein are of type="radio", hides them and appends span elements (of class="buttonRadio") in their place, using the text from their relevant label elements. It also binds click events to the appended span elements, and triggers the change event on the original inputs and also adds the 'checked' class-name to the clicked/touched element, while removing that class it from its siblings:
$('fieldset').each(
function() {
var legend = $(this).find('legend').text();
if ($(this).find('input').length == $(this).find('input[type="radio"]').length) {
var that = $(this),
len = that.find('input[type="radio"]').length;
for (var i = 0; i < len; i++) {
$('<span />')
.text($('label')
.eq(i).text())
.addClass('buttonRadio')
.attr('data-fromID',that.find('input:eq(' + i + ')').attr('id'))
.appendTo(that);
}
}
}).on('click','.buttonRadio',function(){
var id = $(this).attr('data-fromID');
$(this).addClass('checked').siblings().removeClass('checked');
$('#' + id).click().trigger('change');
}).find('label, input[type="radio"]').css('display','none');​
This uses the following CSS to style those elements:
.buttonRadio {
background-color: #fff;
padding: 0.5em 1em;
border: 1px solid #000;
margin: 0.5em 0 0 0;
}
.buttonRadio.checked {
background-color: #ffa;
}​
JS Fiddle demo.
Edited to amend the jQuery a little:
cached the $(this) object a little earlier in this version,
remembered to use the legend variable that I assigned in the first incarnation but forgot to actually use...sigh.
also hid the actual <legend></legend> element:
$('fieldset').each(
function() {
var that = $(this),
legend = that.find('legend').text();
$('<span />').text(legend).addClass('legend').appendTo(that);
if (that.find('input').length == that.find('input[type="radio"]').length) {
var len = that.find('input[type="radio"]').length;
for (var i = 0; i < len; i++) {
$('<span />')
.text($('label')
.eq(i).text())
.addClass('buttonRadio')
.attr('data-fromID',that.find('input:eq(' + i + ')').attr('id'))
.appendTo(that);
}
}
}).on('click','.buttonRadio',function(){
var id = $(this).attr('data-fromID');
$(this).addClass('checked').siblings().removeClass('checked');
$('#' + id).click().trigger('change');
}).find('label, input[type="radio"], legend').css('display','none');​
JS Fiddle demo.
References:
addClass().
attr().
click().
css().
each().
eq().
find().
on().
removeClass().
siblings().
text().
trigger().

Related

Having trouble selecting elements in CSS with elements created in JS

I created some divs with JS like so:
const container = document.querySelector('#container');
for(let i = 1; i < 17; i++) {
var row = document.createElement('div');
row.id = 'r' + i;
row.class = 'row';
container.appendChild(row);
for(let j = 1; j < 17; j++) {
var newDiv = document.createElement('div');
newDiv.id = 'c' + j;
newDiv.class = 'box';
newDiv.textContent = row.id;
row.appendChild(newDiv);
}
}
I'm trying to test the row divs by adding a border to each row class in css like so:
#row {
border: 1px solid green;
}
My question is how come the rows are not showing up with a green border? Am I able to select element from CSS file with elements created in JS?
I was expecting 16 boxes for each of the 16 div elements with class "row".
In the JS use className instead of class.
row.className = 'row'
In the CSS use a . (the # is an id selector)
.row {
border: 1px solid green;
}
You have two issues here...
The first issue is in css, to call a class to style in css you must use the . selector, so to select the row class and give it the style, you need to do this:
.row{
border: 1px solid green;
}
The second issue is in javascript.
JavaScript doesn't have a property called class for the DOM elements, but instead it has two other things to work woth the classes, one is the className property which is just a string that you must handle by yourself when you try to edit it.
And the code in this case will be like that':
row.className = 'row'
And the second is the classList object which has many useful methods like the add, remove, and the contains methods, that make it very easy to add, remove and check for foundation of multiple classes in javascript.
And the code in your case will be:
row.classList.add('row')
Then when you need to remove it you can just use this code:
row.classList.remove('row')
And anytime you try to do some code based on the class foundation, you can check for foundation using this code:
if( row.classList.contains('row') ) {
// Your code here
}
I hope i managed to help.

Vanilla Javascript: Remove toggle class from X element if I click on Y element with the same toggle class

I'm currently working on a sidebar menu where I toggle the "selected" class on a category, which has the classname "sidebar-category".
With jQuery I can easily achieve my desired goal: after toggling the "selected" class (if I click on another category) the previous category gets the class removed and is then applied to the currently clicked category:
$('.sidebar-category').click(function() {
$(".sidebar-category").not(this).removeClass("selected");
$(this).toggleClass('selected');
});
My problem is that for this project I cannot use jQuery and must use vanilla Javascript.
So far I can achieve the toggling easily, but I'm not sure how I can remove the class when clicking on another category using vanilla Javascript. This is my current code:
var selectCategory = document.getElementsByClassName('sidebar-category');
for (var i = 0, l = selectCategory.length; i < l; i++) {
selectCategory[i].onclick = function() {
this.classList.toggle('selected');
}
}
The jQuery code that removes the selected class is equivalent to a loop. So just write that loop in your event listener.
var selectCategory = document.getElementsByClassName('sidebar-category');
for (var i = 0, l = selectCategory.length; i < l; i++) {
selectCategory[i].onclick = function() {
for (var j = 0; j < l; j++) {
if (selectCategory[j] != this) {
selectCategory[j].classList.remove("selected");
}
}
this.classList.toggle('selected');
}
}
Assuming your target environment supports ES2015 (or you transpile your code to support such an environment), a declarative approach using Array.from, filter and forEach can be achieved with the following code:
function toggleSelectedClass(event) {
Array.from(document.getElementsByClassName('sidebar-category'))
.filter(element => element !== event.target)
.forEach(element => {
element.classList.remove('selected')
element.setAttribute('aria-pressed', false);
});
event.target.classList.toggle('selected');
const pressed = event.target.getAttribute('aria-pressed') === 'true';
event.target.setAttribute('aria-pressed', String(!pressed));
}
.sidebar-category {
padding: 5px;
}
.selected {
background: blue;
color: white;
}
<div onclick="toggleSelectedClass(event)">
<button type="button" class="sidebar-category selected" aria-pressed="true">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
<button type="button" class="sidebar-category" aria-pressed="false">Click</button>
</div>
Note: getElementsByClassName returns an HTMLCollection, not an array, so Array.from is required to use the array methods filter and forEach.
Note 2: Keep accessibility in mind when designing such a menu. A good reference for this is https://inclusive-components.design/toggle-button/.
This can be achieved with the Events API in JavaScript.
Using the onClick="" property of an HTML element we can construct a toggling system.
Create a function to handle the click action of the user and pass in the element that has been clicked as the parameter. function toggle(element){...}
Inside that element first fire off an event to clear the selected element(s) using the event named clearselected that will iterate through the elements and set the selected property to false. Thus, semantically deselecting the elements.
Change the selected property of the element passed in the onclick handler to true.
Update the user interface (UI) using an event called updateui that changed the selected element to its desired appearance, and all non-selected elements to their desired appearance using a for loop that iterates through all elements and looks at the selected property.
Down below I have a code snippet that uses vanilla JavaScript to create a toggle system on the UI. It has a very basic HTML that uses the same class names and adds very little CSS to make the demo easier to understand. I hope this is the thing you were looking for!
// Set up the HTML elements in JavaScript
var sidebar = document.getElementsByClassName("sidebar")[0];
var sidebarCategories = document.getElementsByClassName("sidebar-category");
// Add an event listener for clearing the selected elements
sidebar.addEventListener("clearselected", function(e) {
for(var i = 0; i < sidebarCategories.length; i++){
sidebarCategories[i].selected = false;
}
}, false);
// Add an event listener updating the UI to reflect changes
sidebar.addEventListener("updateui", function(e) {
for(var i = 0; i < sidebarCategories.length; i++){
var current = sidebarCategories[i];
if(current.selected){
current.textContent = "selected";
}else{
current.textContent = "";
}
}
}, false);
// Write a on click handler to handle the toggle
function toggle(element){
var event = document.createEvent("Event");
event.initEvent("clearselected", true, true);
element.dispatchEvent(event);
element.selected = true;
var event = document.createEvent("Event");
event.initEvent("updateui", true, true);
element.dispatchEvent(event);
}
.sidebar-category {
width: 100px;
height: 100px;
border: 3px solid black;
margin-bottom: 10px;
line-height: 100px;
text-align: center;
}
<div class="sidebar">
<p>Click the boxes to see the toggle in action</p>
<div class="sidebar-category" onclick="toggle(this)"></div>
<div class="sidebar-category" onclick="toggle(this)"></div>
<div class="sidebar-category" onclick="toggle(this)"></div>
</div>

How would I make specific boxes changes color upon clicking on them?

I'd like to change color of more than one box to purple upon clicking on it. With my current code below, only one box gets colored purple when clicking on it.
I've tried so many different ways to make it work in terms of upon you clicking on any number of boxes, the box should turn purple, but all my attempts have failed.
What am I doing wrong?
function createBoxesDynamically() {
var tileLength = Math.floor(Math.random() * 11);
console.log("tileLength " + tileLength);
var box = new Array(tileLength);
console.log("box" + box);
for (var i = 0; i < box.length; i++) {
box[i] = "box";
}
for (var j = 0; j < box.length; j++) {
var div = document.createElement("div");
div.id = "box";
document.body.appendChild(div);
}
var boxes = document.querySelector("[id^=box]");
boxes.addEventListener("click", function () {
boxes.style.backgroundColor = "purple";
});
}
createBoxesDynamically();
#box {
border: 1px solid;
width: 50px;
height: 50px;
background-color: green;
}
You can't have multiple elements with identical id values, that's why no matter which box you click, the first one is always affected, your .querySelector() call stops looking after finding the first match.
Instead, move the code that sets up the event handler inside the loop where the box is being created and just use this in the click callback to have the callback act upon the box that was clicked. No id necessary. And, because you won't be using ids, you don't need your array or the first loop.
In general, stay away from coding solutions that rely on ids. Yes, they seem precise and easy to use at first, but what you'll find (and you already are) is that they create very brittle solutions that don't scale very well. There are many other ways of referencing and styling elements besides an id.
You should also try to avoid inline styling of elements (setting up styles directly on the style property) as this usually leads to duplication of code and therefore makes the code more difficult to read and maintain. Use CSS classes for as much as you can.
function createBoxesDynamically() {
var tileLength = Math.floor(Math.random() * 11);
console.log("tileLength " + tileLength);
for (var j = 0; j < tileLength; j++) {
var div = document.createElement("div");
div.classList.add("box"); // Add the CSS class to the element
div.addEventListener("click", function () {
this.classList.add("clickColor");;
});
document.body.appendChild(div);
}
}
createBoxesDynamically();
/* Use Classes instead of IDs */
.box {
border: 1px solid;
width: 50px;
height: 50px;
background-color: green;
}
.clickColor { background-color: #800080; }

Updating Inline Styling with removeAttribute() and setAttribute() not updating

Updated inline styling of a certain paragraph tag is not displaying new updates.
I am using the following example that I found on Stack overflow:
var para = document.getElementsByTagName('div');
var len = para.length;
for (var i = 0; i < len; ++i) {
if(para[i].innerHTML.indexOf("SOME TEST") !== -1) {
para[i].removeAttribute('style');
para[i].setAttribute('style', 'FONT-SIZE: 100px !important; FONT-FAMILY: Arial !important; color:red;');
}
}
When I look at the inspector tool, I am able to see the styling I implemented. However, the styling is not taking place.
What am I doing wrong? I am trying to make this work for IE8 and below
You need to use an alternative for old versions of IE, which neither support using setAttribute() to set styles nor event handlers. This also works in other browsers too:
var para = document.getElementsByTagName('div');
var len = para.length;
for (var i = 0; i < len; ++i) {
if(para[i].innerHTML.indexOf("SOME TEST") !== -1) {
para[i].style.cssText = 'FONT-SIZE: 100px !important; FONT-FAMILY: Arial !important; color:red;';
}
}
On the other hand, I agree with the suggestion others have made that class switching is better when you're not using JS to calculate a value dynamically.
A better approach for styling an element using attributes, would be using custom element attributes and specific CSS rules for those attributes.
Note : If you want to pass HTML validations, your attribute names must be prefixed with 'data-'. They should also not contain any uppercase letters.
In the following example, you will see how the styles declared with the [data-myAttribute] CSS selector are applied when the attribute is set to the element :
var myElement = document.getElementById('myElement');
// click event handler compatible with IE8
myElement.onclick = function clickHandler(e){
// toggle the 'data-myAttribute' attribute
if( myElement.hasAttribute('data-myAttribute') ){
myElement.removeAttribute('data-myAttribute');
}else{
myElement.setAttribute('data-myAttribute', true);
}
}
[data-myAttribute]{
text-decoration : underline;
color : red;
}
<div id="myElement">click me</div>

Change backgroundcolour of input after onblur automatically across page

I would like an input field to have the background colour changed after onblur. Automatically for all fields on every page. So I am hoping for a script in the header that will automatically affect all input fields.
Can this be done?
Thanks!
window.onload = function(){
Array.prototype.slice.call(document.getElementsByTagName('input')).forEach(function(element){
element.addEventListener('blur',function(){
//anything here. Notice that both this and element refer to each input element.
})
});
}
document.querySelectorAll or any function returning a NodeList object can be used.
since you start up in an "onblur" state, you should listen to the focus/click event, not the blur event
add css
input{ /*Blurred state*/
background-color: red;
}
.onFocus input{ /*clicked state*/
background-color: green;
}
add some javascript
$(input).
click(function(e){
body.className="onFocus";
}).
blur(function(){
body.className="";
});
It can certainly be done. Because you've demonstrated no attempt, I'm choosing to assume you're willing to support the latest/up-to-date browsers (rather than all legacy browsers):
function colorOnBlur(){
this.style.backgroundColor = '#f00';
}
var inputs = document.querySelectorAll('input');
for (var i = 0, len = inputs.length; i < len; i++){
inputs[i].addEventListener('blur', colorOnBlur);
}
JS Fiddle demo.
Or you can add a new class-name to the elements (rather than changing the style object yourself:
function colorOnBlur(){
this.classList.add('blurred');
}
var inputs = document.querySelectorAll('input');
for (var i = 0, len = inputs.length; i < len; i++){
inputs[i].addEventListener('blur', colorOnBlur);
}
Coupled with the CSS:
input.blurred {
background-color: #f00;
}
JS Fiddle demo.
Obviously, adjust the relevant colours to your own tastes/requirements.
References:
addEventListener().
classList.
document.querySelectorAll().

Categories

Resources