What are the CSS secrets to a flexible/fluid HTML form? - javascript

The below HTML/CSS/Javascript (jQuery) code displays the #makes select box. Selecting an option displays the #models select box with relevant options. The #makes select box sits off-center and the #models select box fills the empty space when it is displayed.
How do you style the form so that the #makes select box is centered when it is the only form element displayed, but when both select boxes are displayed, they are both centered within the container?
var cars = [
{
"makes" : "Honda",
"models" : ['Accord','CRV','Pilot']
},
{
"makes" :"Toyota",
"models" : ['Prius','Camry','Corolla']
}
];
$(function() {
vehicles = [] ;
for(var i = 0; i < cars.length; i++) {
vehicles[cars[i].makes] = cars[i].models ;
}
var options = '';
for (var i = 0; i < cars.length; i++) {
options += '<option value="' + cars[i].makes + '">' + cars[i].makes + '</option>';
}
$("#make").html(options); // populate select box with array
$("#make").bind("click", function() {
$("#model").children().remove() ; // clear select box
var options = '';
for (var i = 0; i < vehicles[this.value].length; i++) {
options += '<option value="' + vehicles[this.value][i] + '">' +
vehicles[this.value][i] +
'</option>';
}
$("#model").html(options); // populate select box with array
$("#models").addClass("show");
}); // bind end
});
.hide {
display: none;
}
.show {
display: inline;
}
fieldset {
border: #206ba4 1px solid;
}
fieldset legend {
margin-top: -.4em;
font-size: 20px;
font-weight: bold;
color: #206ba4;
}
fieldset fieldset {
position: relative;
margin-top: 25px;
padding-top: .75em;
background-color: #ebf4fa;
}
body {
margin: 0;
padding: 0;
font-family: Verdana;
font-size: 12px;
text-align: center;
}
#wrapper {
margin: 40px auto 0;
}
#myFieldset {
width: 213px;
}
#area {
margin: 20px;
}
#area select {
width: 75px;
float: left;
}
#area label {
display: block;
font-size: 1.1em;
font-weight: bold;
color: #000;
}
#area #selection {
display: block;
}
#makes {
margin: 5px;
}
#models {
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<div id="wrapper">
<fieldset id="myFieldset">
<legend>Cars</legend>
<fieldset id="area">
<label>Select Make:</label>
<div id="selection">
<div id="makes">
<select id="make"size="2"></select>
</div>
<div class="hide" id="models">
<select id="model" size="3"></select>
</div>
</div>
</fieldset>
</fieldset>
</div>

It's not entirely clear from your question what layout you're trying to achieve, but judging by that fact that you have applied "float:left" to the select elements, it looks like you want the select elements to appear side by side. If this is the case, you can achieve this by doing the following:
To centrally align elements you need to add "text-align:center" to the containing block level element, in this case #selection.
The position of elements that are floating is not affected by "text-align" declarations, so remove the "float:left" declaration from the select elements.
In order for the #make and #model divs to sit side by side with out the use of floats they must be displayed as inline elements, so add "display:inline" to both #make and #model (note that this will lose the vertical margin on those elements, so you might need to make some other changes to get the exact layout you want).
As select elements are displayed inline by default, an alternative to the last step is to remove the #make and #model divs and and apply the "show" and "hide" classes to the model select element directly.

Floating the select boxes changes their display properties to "block". If you have no reason to float them, simply remove the "float: left" declaration, and add "text-align: center" to #makes and #models.

Related

Dynamically create a matrix of radiobutton from two textbox inputs

I would like to create a matrix of radio buttons based on two arrays one having label and count for rows and another one having label and count for column.
These arrays are obtained from two textboxes, where users enters texts separated by semicolon:
<input type="text" name="criteria" id="criteria" class="Textbox autobox default" value="row1;row2;row3;row4" autocomplete="off">
<input type="text" name="levels" id="levels" class="Textbox autobox default" value="level1;level2;level3;level4;level5" autocomplete="off">
Then I tried to create radio buttons dynamically for a row using:
var array1 = $('#criteria').val().split(";");
var array2 = $('#levels').val().split(";");
for (j = 0; j < array2.length; j++) {
for (i = 0; i < array1.length; i++) {
var radioBtn = $('<input type="radio" name="rbtnCount" />');
radioBtn.appendTo('#matrix');
}
$('#matrix').append("<br/>");
}
I manage to produce rows of radio buttons but I could not get for each new row as new group and with labels.
I expected a matrix of radio buttons like in the following figure:
Users should be able to select one in each row therefore each row is in different groupings so that selection in one row does not affect other.
Different row wise groupings can be made by setting same name for every radio element in that row. In the following snippet, names of radio buttons are set from the criteria array elements.
The id for every radio button should be unique, hence a combination of row and column iterators can be made to set up their ids (e.g. '00','01','02', etc.).
It is advised not to make too many DOM update calls by using element.append() inside loops. Instead, you can form your entire HTML string and append it at the very end of your script.
$('#criteria').change(function() {
updateMatrix();
});
$('#levels').change(function() {
updateMatrix();
});
updateMatrix();
function updateMatrix() {
var innerHTML = "";
var criterias = $('#criteria').val().split(";");
var levels = $('#levels').val().split(";");
$.each(criterias, function(i) {
if (i === 0) {
innerHTML += "<tr><th></th>";
$.each(levels, function(j) {
innerHTML += `<th> ${levels[j]} </th>`;
});
innerHTML += "</tr>";
}
innerHTML += "<tr>";
$.each(levels, function(j) {
if (j === 0) innerHTML += `<td> ${criterias[i]} </td>`;
innerHTML += `<td><input type="radio" name="${criterias[i]}" id="${i}${j}"></td>`;
});
innerHTML += "</tr>";
});
$('#matrix').html(innerHTML);
}
body {
font-family: Arial, Helvetica, sans-serif;
}
div {
margin-bottom: 10px;
}
.text-label {
display: block;
text-transform: uppercase;
font-size: 12px;
font-weight: bold;
padding: 3px 5px;
}
.textbox {
padding: 10px;
width: 300px;
}
table {
border-collapse: collapse;
text-transform: uppercase;
font-size: 10px;
border: 1px solid #333;
margin-top: 20px;
}
table input {
display: block;
margin: 0 auto;
}
th,
td {
text-align: left;
padding: 10px 20px;
}
th {
background-color: #333;
color: white;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<span class="text-label">Criteria</span>
<input class="textbox" type="text" name="criteria" id="criteria" value="row1;row2;row3;row4" autocomplete="off">
</div>
<div>
<span class="text-label">Levels</span>
<input class="textbox" type="text" name="levels" id="levels" value="level1;level2;level3;level4;level5" autocomplete="off">
</div>
<table id="matrix">
</table>

Clone div based on content of span

There are random number of div's as show below, I am trying to clone these div on click. when cloning I want to change the content to actual content + no of clones it has (based on content of span , not the id or classes of "clone-this")
eg.
If I click the first "chrome" div, since the body already have "chrome (1) and chrome (2)" , div with content "chrome (3)" Should appear .
If I click the 2nd div ie. "Mozilla Firefox", since there is no cloned version, a div with content "Mozilla Firefox (1)" should appear.
and so on.
I tried to make this, but when i clone the count is based on class , not the content . so clicking on "chrome" div will clone "chrome (5)" not "chrome (3)" .
Also in my implementation when i click the "chrome (1)" div, it will clone as "chrome (1)(5)" . I want this to be like "chrome (3)"
how can i achieve this?
note that there will be any number of divs at first. 5 is just for and example.
jsfiddle here
$(document).on('click', '.clone-this', function(){
var CloneContainer = $(this).clone();
var no = $('.clone-this').size();
CloneContainer.html(CloneContainer.html() + " (" + no + ")");
CloneContainer.appendTo('body');
});
.clone-this{
padding: 15px;
width: 100px;
text-align: center;
border: 1px solid #ccc;
margin: 10px auto;
cursor: pointer;
color: #444;
border: 1px solid #ccc;
border-radius: 3px;
font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="clone-this"><span>Chrome</span></div>
<div class="clone-this"><span>Mozilla Firefox</span></div>
<div class="clone-this"><span>Safari</span></div>
<div class="clone-this"><span>Chrome (1)</span></div>
<div class="clone-this"><span>Chrome (2)</span></div>
To accomplish that, you should check "content" of each item and count the number of elements which have same text. But, there is one problem here; each element (for example Chrome, Chrome (1), Chrome (2)) has different content. So, you may split the text using parenthesis or you may use RegEx (recommended).
$(document).on('click', '.clone-this', function(){
var CloneContainer = $(this).clone();
var content = CloneContainer.find('span').html().split(' (')[0];
var no = $(".clone-this:contains('"+content+"')").size();
CloneContainer.html( CloneContainer.html() .split(' (')[0] + " (" + no + ")" );
CloneContainer.appendTo('body');
});
.clone-this{
padding: 15px;
width: 100px;
text-align: center;
border: 1px solid #ccc;
margin: 10px auto;
cursor: pointer;
color: #444;
border: 1px solid #ccc;
border-radius: 3px;
font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="clone-this"><span>Chrome</span></div>
<div class="clone-this"><span>Mozilla Firefox</span></div>
<div class="clone-this"><span>Safari</span></div>
<div class="clone-this"><span>Chrome (1)</span></div>
<div class="clone-this"><span>Chrome (2)</span></div>
On the snippet above, you may see basic version of it. But you MUST consider the "similar content" issue like following.
Chrome
Chrome Mobile
Firefox
Firefox Mobile
Here is another way to get you going. I "trim" the clicked div to its base name and then loop through the divs and get the length of all which contain the same base name.
After that I modify the cloned element to fill in the right count of the cloned element appropriately:
var regExp = /\([0-9]+\)/;
$('.clone-this').click(function(e){
var target = e.target.textContent;
var matches = regExp.exec(target);
var elements = $('.clone-this');
var count = elements.length;
var index = 0;
if (null != matches) {
target = matches.input.substr(0, matches.input.lastIndexOf(" "));
}
for(var i = 0; i < count; i++){
index += (elements[i].textContent.indexOf(target) > -1) ? 1: 0;
}
var CloneContainer = $(this).clone();
CloneContainer.html(CloneContainer.html().split('(')[0] + "(" + index + ")" );
CloneContainer.appendTo('body');
});
.clone-this{
padding: 15px;
width: 100px;
text-align: center;
border: 1px solid #ccc;
margin: 10px auto;
cursor: pointer;
color: #444;
border: 1px solid #ccc;
border-radius: 3px;
font-family: monospace;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="clone-this"><span>Chrome</span></div>
<div class="clone-this"><span>Mozilla Firefox</span></div>
<div class="clone-this"><span>Safari</span></div>
<div class="clone-this"><span>Chrome (1)</span></div>
<div class="clone-this"><span>Chrome (2)</span></div>

Replace selection inputs with clickable images

MY code below lets me take an HTML selection and provide a more user friendly image clickable version. When an image is clicked, it selects the proper value in a hidden selection filed in the DOM.
I just need help in adjusting my code below to work on a selection that is on the page multiple times.
If it is on the page 10 times, I need to run this code 10 times.
I am not sure how to target each one separately though
Preview
HTML Selection gets turned into clickable Images like this below. The JavaScript reads the HTML Selection filed already on the page and clones it and replaces each value with images. It then hides the original selection field. When an image is clicked on, and appears selected, it is using JavaScript to select that value in the real hidden selector as well!...
Live Demo
http://jsfiddle.net/jasondavis/ov1a4apc/
JavaScript
jQuery(document).ready(function($) {
if ($('#page_template').length) {
//$('#page_template').hide().after('<div id="page_template_visual"></div>');
$('#page_template').after('<div id="page_template_visual"></div>');
$('#page_template option').each(function() {
var classname = $(this).val().replace('.php', '');
if ($(this).is("[selected]")) {
classname = classname + ' selected';
}
$('#page_template_visual').append('<small></small>' + $(this).text() + '');
});
if (!$('#page_template option[selected]').length) {
$('#page_template_visual a:first-child').addClass('selected');
}
$('#page_template_visual a').on('click', function() {
$('#page_template_visual a').removeClass('selected');
theValue = $(this).addClass('selected').attr('href');
$("#page_template").val(theValue).attr('selected', true);
return false;
});
}
});
HTML Select
<select name="page_template" id="page_template" selected="selected">
<option value="default">Default Template</option>
<option value="custom-archives.php">Archives Template</option>
<option value="wpi/pdf_quote_bold.php">Bold</option>
<option value="SOONcontact.php">Contact</option>
<option value="page-invoice.php">Invoice</option>
<option value="wpi/pdf_quote_modern.php">Modern</option>
<option value="wpi/pdf_quote.php">Traditional</option>
</select>
CSS
#page_template{
/* display: none; */
}
#page_template_visual {
margin: 0 -10px;
}
#page_template_visual a {
display: inline-block;
width: 129px;
height: 100px;
margin: 0 5px 5px;
text-align: center;
color: #333333;
font-weight: bold;
text-decoration: none;
background: url('http://i.imgur.com/7S9yzTY.png') no-repeat left top;
}
#page_template_visual a small {
height: 64px;
width: 119px;
display: inline-block;
margin: 5px 5px 5px 5px;
}
/* You can define images for the options here based on the classnames */
#page_template_visual a.template-both-sidebar-page {background-position: right -100px;}
#page_template_visual a.template-left-sidebar-page {background-position: right top;}
#page_template_visual a.template-right-sidebar-page {background-position: left -100px;}
#page_template_visual a.selected {
color: #559a08;
text-shadow: 1px 1px 0px #fff;
}
#page_template_visual a.selected small {
background: rgba(106,189,15,0.1) url('http://i.imgur.com/P0E1jmh.png') no-repeat center;
}
First, you need to change the page_template and page_template_visual ids to classes (in the HTML, JavaScript & CSS).
Then loop through all the elements with the page_template class, like this:
jQuery(document).ready(function($) {
$('.page_template').each(function() {
var $select = $(this);
// Keep a reference to this element so you can use it below.
var $visual = $('<div class="page_template_visual"></div>');
$select.after($visual);
$select.find('option').each(function() {
var $option = $(this);
var classname = $option.val().replace('.php', '');
if ($option.is("[selected]")) {
classname = classname + ' selected';
}
$visual.append('<small></small>' + $option.text() + '');
});
if (!$select.find('option[selected]').length) {
$visual.find('a:first-child').addClass('selected');
}
// The next line could have been:
// $visual.find('a').on('click', function() {
// But instead it uses event delegation, so only one
// event handler is registered, instead of one for each <a>.
$visual.on('click', 'a', function() {
$visual.find('a').removeClass('selected');
var value = $(this).addClass('selected').attr('href');
$select.val(value);
return false; // You don't need this, unless you really don't want the click event to bubble up.
});
});
});
jsfiddle

display a div below a selected input field? No JQuery

how to display a div everytime a user focus on a input field. there is already a div and it is hidden. the position of the div will change depending on the position of the selected field and it will be display below
this is my code
formFieldListWrapper.style.top = ((((formSelectedFieldInput.offsetTop > (formWrapper.offsetHeight/2))?((formSelectedFieldInput.offsetTop-(formWrapper.offsetHeight/2))-(formSelectedFieldInput.offsetHeight+formWrapper.offsetHeight*0.02)):(formSelectedFieldInput.offsetTop))/formWrapper.offsetHeight)*100) + "%";
formFieldListWrapper.style.left = ((formSelectedFieldInput.offsetLeft/formWrapper.offsetWidth)*100) + "%";
Why use javascript? This could be chieved by using CSS only
HTML
<div class="holder">
<input type="text" />
<div class="dropdown">
<p>Testing</p>
<p>Css ONLY</p>
<p>Dropdown</p>
</div>
</div>
CSS
.holder {
position: relative;
}
.dropdown {
position: absolute;
border: 1px solid red;
display: none;
}
input:focus + .dropdown {
display: block;
}
UPDATE
little bit misred the question, if You need to position div dynamically like in this fiddle, You cloud use:
HTML
<div class="holder">
<input type="text" />
</div>
<div class="holder" style="margin-top: 30px;">
<input type="text" />
</div>
<div class="dropdown">
<p>Testing</p>
<p>Css ONLY</p>
<p>Dropdown</p>
</div>
CSS
.holder {
position: relative;
}
.dropdown {
position: absolute;
border: 1px solid red;
display: none;
z-index: 1;
background: white;
}
input:focus + .dropdown {
display: block;
}
Javascript to position dropdown div
var inputs = document.querySelectorAll('input');
for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener('focus', function(){
this.parentNode.appendChild(document.querySelector('.dropdown'));
});
}
Try the following:
formSelectedFieldInput.addEventListener("focus", setDivToInput, false);
function setDivToInput(e)
{
var inputElement = e.target; //e.target refers to the element that fired the event.
formFieldListWrapper.style.top = inputElement.offsetTop + formFieldListWrapper.offsetHeight + "px";
formFieldListWrapper.style.left= inputElement.offsetLeft + "px";
formFieldListWrapper.style.display = "block";
}
The first line adds a focus event to the input. This sets the div to the input based upon it's position on the page. This is very basic and doesn't behave well when the div runs of the screen. You need to add logic for that.
Now for multiple inputs in a form
var nodes = form.querySelectorAll("input"); //replace with your form element
for (var i = 0; i < nodes.length; ++i)
{
nodes[i].addEventListener("focus", setDivToInput, false);
}
function setDivToInput(e)
{
var node = e.target;
formFieldListWrapper.style.top = node.offsetTop + formFieldListWrapper.offsetHeight + "px";
formFieldListWrapper.style.left= node.offsetLeft + "px";
formFieldListWrapper.style.display = "block";
}
This code sets the focus event to all inputs in the form.

Convert hierarchical JSON files to hierarchical jQuery divs

How do I loop through two PARENT-CHILD-relationship (on simple ID PKEY and FKEY) JSON files and display them as a list of divs that are:
hierarchical - where child/FKEY divs only appear under the parent/PKEY div (show up as parent-child-child, parent-child-child-child, etc.)
expandable - these child/FKEY divs are display:none until you click the parent/PKEY div; i.e., items appear/disappear when you click the PKEY div, using jQuery's $(panelID).slideToggle(speed) method
able to be toggled with a separate checkbox div if the last key-value pair in the parent div OR child div exists and has key="DEPRECATED"
sortable - Just Kidding
jQuery offers me both parseJSON and cool display functions, and I give it atrociously horrible JS-debugging skills in return.
Edit: Here are the two JSON files in question:
types.json:
{"objtype":[{"NAME":"Animal","ID":"15","DEPRECATED":""},{"NAME":"Vegetable","ID":"8"},{"NAME":"Mineral","ID":"2","DEPRECATED":""}]}
objs.json:
{"objinstance":[{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Fruit salad consisting of oranges and mangoes","OBJID":"454","DATEEXPIRES":"2014-09-01 00:00:00.0","DEPRECATED":""},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Spicy V-8 juice","OBJID":"499","DATEEXPIRES":"2015-01-02 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Rental agreement for new apartment","OBJID":"2885","DATEEXPIRES":"2015-08-25 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Salt","OBJID":"1033","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Koko the Monkey","OBJID":"68","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Bubbles the Clown","OBJID":"69","DATEEXPIRES":"","DEPRECATED":""}]}
Here is an extremely simple example of how you could generate HTML markup based on your data in JSON.
Algorithm:
Parse JSON string into Javascript objects
Iterate parent data
For each parent data, create parent div and add required content into it.
Iterate child data, search for common id
For each child data which matches the parent id, create child div, add required content into it, and finally append to the parent div
Append parent div to a container or body
Rinse, lather, repeat
Create CSS styles as per your taste
.
Demo Fiddle: http://jsfiddle.net/abhitalks/h3nbwc1f/
Snippet:
var typesString = '{"objtype":[{"NAME":"Animal","ID":"15","DEPRECATED":""},{"NAME":"Vegetable","ID":"8"},{"NAME":"Mineral","ID":"2","DEPRECATED":""}]}';
var objsString = '{"objinstance":[{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Fruit salad consisting of oranges and mangoes","OBJID":"454","DATEEXPIRES":"2014-09-01 00:00:00.0","DEPRECATED":""},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"8","OBJNAME":"Spicy V-8 juice","OBJID":"499","DATEEXPIRES":"2015-01-02 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Rental agreement for new apartment","OBJID":"2885","DATEEXPIRES":"2015-08-25 00:00:00.0"},{"DATEBOUGHT":"2014-08-26 00:00:00.0","OBJTYPEID":"2","OBJNAME":"Salt","OBJID":"1033","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Koko the Monkey","OBJID":"68","DATEEXPIRES":"","DEPRECATED":""},{"DATEBOUGHT":"","OBJTYPEID":"15","OBJNAME":"Bubbles the Clown","OBJID":"69","DATEEXPIRES":"","DEPRECATED":""}]}';
var types = JSON.parse(typesString);
var objs = JSON.parse(objsString);
types.objtype.forEach(function(item, idx) {
var $parent = $("<div class='parent' />");
var $label = $("<label>").text(item.ID + ': ' + item.NAME).attr('for', 'c' + idx);
var $input = $('<input type="checkbox">').attr('id', 'c' + idx);
$parent.append($label);
$parent.append($input);
objs.objinstance.forEach(function(item2) {
if (item2.OBJTYPEID == item.ID) {
var $child = $("<div class='child' />");
var txt2 = item2.OBJID + ': ' + item2.OBJNAME;
$child.text(txt2);
$parent.append($child);
}
});
$("#wrap").append($parent);
});
div#wrap {
font-family: helvetica, sans-serif;
font-size: 17px;
}
div.parent {
border: 1px solid blue;
padding: 8px; margin: 4px;
}
div.child {
border: 1px solid green;
font-size: 15px;
padding: 0px; margin: 0px;
opacity: 0; height: 0px;
transition: all 250ms;
}
label {
cursor: pointer;
}
input[type=checkbox] {
display: none;
}
input[type=checkbox]:checked ~ div.child {
padding: 8px; margin: 8px;
opacity: 1; height: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap"></div>

Categories