I have the following html that is rendered by a django. Here is an instance of how it could be
html
<div class="treatment container">
<div class="row">
<div class="treatment-phrase col-md-4">
<form action="" method="post" class="inline">
<input type="hidden" name="csrfmiddlewaretoken" value="hbdqhZuNYn83WvZg110TCiENekDqWjUD">
<p class="text-info" data-id="2">TR - 35</p>
<button class="btn btn-default btn-sm edit-phrase">Edit</button>
</form>
</div>
</div>
<div class="row">
<div class="treatment-phrase col-md-4">
<form action="" method="post" class="inline">
<input type="hidden" name="csrfmiddlewaretoken" value="hbdqhZuNYn83WvZg110TCiENekDqWjUD">
<p class="text-info" data-id="3">TR - 34</p>
<button class="btn btn-default btn-sm edit-phrase">Edit</button>
</form>
</div>
</div>
</div>
The css
.panel-body { padding:0px; }
.panel-body table tr td { padding-left: 15px }
.panel-body .table {margin-bottom: 0px; }
.panel-group,
.settings{
padding-top:2em;
}
.diagnosis-phrase,
.treatment-phrase,
.category-item{
padding-bottom: 1em;
padding-top: 0.5em;
border: 1px solid black;
margin-bottom: 0.5em;
}
.diagnosis-phrase input[type="text"],
.treatment-phrase input[type="text"],
.category-item input[type="text"]{
margin-bottom:0.5em;
}
.category-item p{
padding-left: 0.5em;
padding-bottom:0.3em;
border-radius:0.5em;
width:50%;
}
and js
$("#save-phrase").on('click', function (event) {
form = $("form#add-phrase")
form.submit();
});
$(".edit-phrase").on('click', function(event){
event.preventDefault();
var inputBox;
var form = $(this).parent('form');
var p = $(this).siblings('p');
var input = '<input type="text" data-id="'+p.attr('data-id')+'" class="form-control input-sm col-md-4" id="id_phrase" name="phrase" value="'+p.text()+'">';
console.log(input);
if($(this).text() === 'Edit'){
p.replaceWith(input);
form.append('<button name="delete" class="btn btn-default btn-sm">Delete</button>');
form.append('<input type="submit" name="submit" class="btn btn-default btn-sm" value="Save">');
$(this).text('Cancel');
}else{
console.log(p);
inputBox = $(this).siblings('input#id_phrase');
console.log(inputBox);
p.text(inputBox.val());
inputBox.replaceWith('<p class="text-info" data-id="'+inputBox.attr('data-id')+'">'+inputBox.val()+'</p>');
$(this).siblings('input[type="submit"]').remove();
$(this).siblings('button').remove();
$(this).text('Edit');
}
});
What it does is the following:
It replaces a p dom Element with an input element part of a form and posts the editing the phrase or deleting it (if deleted is pressed) Everything works as it should except for one thing. When user hits cancel it replaces the input box with the previous p. But the way I have written the code the older p is lost so when user cancels the value of p that replaces it is the last value typed when it should be the original one (before editing). How can I save the old value. I can't use one global or two because, the phrases are added dynamically. Note that user could be editing three phrases at the same time (but he can save only one at a time). Do you think that is better if editing is limited to one phrase at a time?That would solve the problem of saving the inital value of the phrase before editing.
Here is the bootply of it.
Since you've got a nice id there, how about a hash table
var cache = {};
when needing to cache
cache[inputBox.attr('data-id')] = p.clone();
when you want to retrieve get the old version of the p back grab it from the hash table using the id.
if you want to store multiple versions of a p then use the hash table and have each element be an array implemented as a stack
cheers
I've edited a previous answer to fit this question:
When the p is edited, make a clone of the element for the future, then replace the element with the copy later. By storing the full clone of the p in its own data attribute, it keeps its own history. You can do multiple "undo" clicks since it will continue to pop its own history from its data.
$('.edit-phrase').on('click', function() {
var p = $(this).siblings('p');
p.data('my_clone', $(p).clone(true));
// continue with rest of the logic
});
$('.cancel-edit').on('click', function() {
var p = $(this).siblings('p');
p.replaceWith($(p).data('my_clone'));
// continue with rest of the logic
});
Documentation:
clone
replaceWith
Related
Ive been thinking about this for days... seems simple but I can't wrap my head around it!
We want to make a simple booking form, where people chose a day and then see two columns of available time slots. I already generate a lost of these.
Now I need to display this in buttons, so they can be pressed and only 1 is selected. So if they choose 2pm Wednesday, and then another, the first goes back to the standard color...
This value needs to be loaded in a hidden field to pass on to the next page.
Having searched it seems like the colors are best done in jquery and the hidden field can be populated easily with vanilla js, that part I have working... Help, how add the color change?
ps this is on a bootstrap 3.4 template, not that that should matter but maybe
<input type="button" id = "booktime" onclick="change(this)" class="btn btn-default" value=" & thishour & ">
function change(bookingtime) {
document.getElementById("myInput").value= bookingtime.value;
}
var links = $('#booktime');
links.click(function() {
links.css('background-color', 'white');
$(this).css('background-color', 'purple');
});
Consider the following HTML and jQuery example.
$(function() {
$(".booking label").click(function() {
var $self = $(this).parent();
$("input", $self).trigger("click");
$(".checked").removeClass("checked");
$self.addClass("checked");
});
$("form").submit(function(e) {
e.preventDefault();
var formData = new FormData(this);
for (var pair of formData.entries()) {
console.log(pair[0] + ', ' + pair[1]);
}
});
});
.booking ul {
list-style: none;
padding: 0;
width: 100px;
}
.booking li {
border: 1px outset rgb(224, 224, 224);
border-radius: 6px;
background: #eee;
padding: 7px;
text-align: center;
margin-bottom: 3px;
font-family: Arial, sans-serif;
}
.booking li.checked {
background: #aaf;
}
.booking li:hover {
background: #ccc;
}
.booking li input {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<div class="booking">
<ul>
<li>
<input type="radio" id="time-0000" name="time" value="12:00">
<label for="time-0000">12:00 AM</label>
</li>
<li>
<input type="radio" id="time-0100" name="time" value="01:00">
<label for="time-0100">1:00 AM</label>
</li>
<li>
<input type="radio" id="time-0200" name="time" value="02:00">
<label for="time-0200">2:00 AM</label>
</li>
<li>
<input type="radio" id="time-0300" name="time" value="03:00">
<label for="time-0300">3:00 AM</label>
</li>
<li>
<input type="radio" id="time-0400" name="time" value="04:00">
<label for="time-0400">4:00 AM</label>
</li>
</ul>
</div>
<button type="submit">Save</button>
</form>
Most of the User Interface is all CSS. You can make it a bit mo9re custom and include a better look and feel with additional JavaScript. The default function of the Radio Button will help.
Radio buttons are normally presented in radio groups (a collection of radio buttons describing a set of related options). Only one radio button in a group can be selected at the same time.
This will help each button retain a State, either Checked or Unchecked. only one can be checked at a time, so we can simple clear the Styling from any other and apply it to the one clicked upon.
I have an already existing form in my code which includes 2 text fields and a submit button.
I have also added an “add” button which when clicked should add a new form below.How do I achieve this using Javascript.
How do I add a new form by clicking on the add button?
you could use jquery $.clone() function so when you hit the button the form will be cloned and then $.append() to the parent div
this will clone the form with the data , if you want something without the data you should clone the form in the start of the script.
You could use a templating engine like {{ mustache }} to create a form template and inject an auto-incrementing ID into it.
Note: If you want more logic, customization, or compiled templates, you can use handlebars.
var FORM_ID_INCR = 1; // Ever-increasing couter
document.getElementById('add-form-btn').addEventListener('click', function(e) {
createAndAppendNewContactForm();
});
function createAndAppendNewContactForm() {
let viewModel = { formId : FORM_ID_INCR++ };
let template = document.getElementById('form-template').innerHTML;
let renderedHtml = Mustache.render(template, viewModel);
let node = document.createRange().createContextualFragment(renderedHtml);
document.getElementById('form-container').appendChild(node);
}
.form-field {
margin-bottom: 0.5em;
}
.form-field label {
display: inline-block;
font-weight: bold;
width: 6em;
}
.contact-form {
border: 1px solid #DDD;
padding: 0.5em;
margin-bottom: 0.5em;
}
#form-container {
margin-bottom: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.1.0/mustache.min.js"></script>
<script id="form-template" type="text/html">
<form id="form-{{formId}}" class="contact-form">
<h2>Form #{{formId}}</h2>
<div class="form-field">
<label>First Name</label>
<input type="text" name="firstName"/>
</div>
<div class="form-field">
<label>Last Name</label>
<input type="text" name="lastName"/>
</div>
<input type="submit" />
</form>
</script>
<body onload="createAndAppendNewContactForm()">
<h1>Forms</h1>
<div id="form-container"></div>
<button id="add-form-btn">Add Form</button>
</body>
So I have a form that allows for people to give reviews. They have to enter their name, email, and review in the input forms. I want to take that information and post it onto the site sidebar. Whenever I try, all I get is "object Object" in the sidebar, never what was place inside the input form. I have four questions
How do I pull the value from the form inputs and place them on the sidebar?
How do I place the new review under the review before?
How do I add the style to the review?
How do I empty the input forms after the review has been submitted?
JFIDDLE LINK
HTML:
Our Reviews
<ul class="review-list" id="sidebar-review-list">
<li class="review">
<p>
Cupcake ipsum dolor sit amet. Lemon drops topping carrot cake. Jujubes pudding chocolate
cookie I love marshmallow I love toffee.
</p>
Jon Smith
</li>
</ul>
<form id="review-form" class="pure-form">
<fieldset>
<div class="pure-control-group">
<input type="text" name="name" class="pure-input-1" id="name" placeholder="Name">
</div>
<div class="pure-control-group">
<input type="email" name="email" class="pure-input-1" id="email" placeholder="Email">
</div>
<div class="pure-control-group">
<textarea name="review" class="pure-input-1" id="review" placeholder="Review"></textarea>
</div>
<button type="submit" class="pure-button pure-button-primary" id="submit-review">Submit Review</button>
</fieldset>
</form>
</section>
CSS
.pure-control-group {
margin-bottom: 10px;
}
.reviews {
margin-bottom: 20px;
}
.review-list {
list-style-type: none;
margin: 0;
padding: 0;
}
.review {
background: #4faac9;
padding: 1px 10px 10px;
color: #fff;
border-radius: 6px;
margin-bottom: 10px;
}
.review a {
color: #176075;
font-weight: bold;
text-decoration: none;
}
JQUERY:
;(function($) {
var $sidebar_review_list = $("#sidebar-review-list");
var $review_form = $("#review-form");
var $name = $("a");
var $email = $("href");
var $review = $("p");
//get a reference to the submit buttons
var $submit_review = $('#submit-review');
var $sidebar_review_list = $('#sidebar-review-list');
//function that will create the reviews
var submit_review = function() {
var $li = $('<li>');
var $p = $('<p>');
var $a = $('<a>');
//set the value
$p.text($review);
$a.text($name);
$a.attr('href', $email);
$li.append($p);
$li.append($a);
$sidebar_review_list.append($li);
};
// add an event listener on the click event of the submit button
$('#submit-review').on('click', function(e) {
e.preventDefault();
submit_review();
});
})(window.jQuery);
You haven't selected jQuery framework in the fiddle, so nothing works.
$p.text($review); // invalid
For selecting an element with id review use $('#review');
After fixing this, $p.text($('#review')); will set the whole jQuery
object of #review element as p's text, hence you get [object object]..
For selecting the value inside it the #review element, use $('#review').val();
so the above line in proper syntax would be $p.text($('#review').val());
same in the case of rest of the code.
1) As mentioned above use val() function to select the value
2) Since you are appending new review to the same container that holds previous review, it automatically comes below the previous review in normal flow.
3) For adding style you can use .css() function or for adding a css class addClass() function.
4) you can use reset() function to manually clear the form after submission.
fiddle
You can get the contents of the form like this:
var form = $('#review-form');
form.each(function() {
alert($(this).attr('name') + ' = ' + $(this).val());
});
Here is the code I have: http://jsfiddle.net/Draven/rEPXM/23/
I'd like to know how I can hide that Add submit button until I click the + image to add input boxes to the form.
I don't want to add the submit button next to the input box because I want to be able to add multiple input boxes and submit them all when I click Add.
HTML
<div id="left">
<div class="box">
<div class="boxtitle"><span class="boxtitleleftgap"> </span><span class="boxtitlebulk"><span class="boxtitletext">Folders</span><div style="float: right; margin-top: 4px;"><div class="addplus"> </div></div></span></div>
<div class="boxcontent">
<form method="post" id="folderform" action="page.php?action=list-volunteer-apps" name="folderform">
<a class="even" href="page.php?action=list-volunteer-apps&folder=2">Folder 2 <span class="text">(1)</span></a><a class="even" href="page.php?action=list-volunteer-apps&folder=1">Folder 1 <span class="text">(0)</span></a>
<div id="foldercontainer"><input type="submit" value="Add"></div>
</form>
</div>
</div>
</div>
jQuery
function AddFolder() {
$('#foldercontainer').append('<input name="folder[]" type="text" size="20" />');
}
Just give the button an ID, and make it start hidden
<input type="submit" id="addButton" value="Add" style="display: none;">
Then use the show() jQuery method:
$("#addButton").show();
http://jsfiddle.net/TcFhy/
Here's a way you could do this... also, cleaned up the method used for making these input boxes a bit:
http://jsfiddle.net/mori57/4JANS/
So, in your html you might have:
<div id="foldercontainer">
<input id="addSubmit" type="submit" value="Add">
<input id="folderName" name="folder[]" type="text" size="20" style="" />
</div>
and your CSS might be:
#foldercontainer #addSubmit {
display:none;
}
#foldercontainer #folderName {
display:none;
width: 120px;
background: #FFF url(http://oi47.tinypic.com/2r2lqp2.jpg) repeat-x top left;
color: #000;
border: 1px solid #cdc2ab;
padding: 2px;
margin: 0px;
vertical-align: middle;
}
and your script could be:
// set up a variable to test if the add area is visible
// and another to keep count of the add-folder text boxes
var is_vis = false,
folderAddCt = 0;
function AddFolder() {
if(is_vis == false){
// if it's not visible, show the input boxes and
$('#foldercontainer input').show();
// set the flag true
is_vis = true;
} else {
// if visible, create a clone of the first add-folder
// text box with the .clone() method
$folderTB = $("#folderName").clone();
// give it a unique ID
$folderTB.attr("id","folderName_" + folderAddCt++);
// and append it to the container
$("#foldercontainer").append($folderTB);
}
}
I moved the button out of the folder wrap, and I am showing it when you add a new folder. This way the button will stay at the bottom when adding new folders. I also removed the inline style, and replaced it with a class.
This is used to display the button, just add it to the AddFolder() function:
$('#addBtn').show();
I am hiding it with CSS like this:
#addBtn { display: none;}
I moved the button out of the #foldercontainer, this way it will always stay at the bottom when you add multiple folders, as you wanted:
<div id="foldercontainer"></div>
<input id="addBtn" type="submit" value="Add">
Look here for the jsFiddle: http://jsfiddle.net/kmx4Y/1/
$('form#folderform input[type=submit]').hide();
Then show the add button after you click the submit
http://jsfiddle.net/SQh8L/
The site is here
I have opt to using the radiobutton's labels as customized buttons for them. This means the radio inputs themselves are display:none. Because of this, the browsers don't tab stop at the radio labels, but I want them to.
I tried forcing a tabindex to them, but no cigar.
I have came up with just putting a pointless checkbox right before the labels, and set it to width: 1px; and height 1px; which seems to only really work on chrome & safari.
So do you have any other ideas for forcing a tab stop at those locations without showing an element?
Edit:
Just incase someone else comes by this, this is how I was able to insert small checkboxes into chrome & safari using JQuery:
if ($.browser.safari) {
$("label[for='Unlimited']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
$("label[for='cash']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
$("label[for='Length12']").parent().after('<input style="height:1px; width:1px;" type="checkbox">');
}
Note: $.browser.webkit was not becoming true...so I had to use safari
a working solution in my case to enable tab selection / arrow navigation was to set the opacity to zero rather than a "display: none"
.styled-selection input {
opacity: 0; // hide it visually
z-index: -1; // avoid unintended clicks
position: absolute; // don't affect other elements positioning
}
Keep the radio input hidden, but set tabindex="0" on the <label> element of reach radio input.
(A tab index of 0 keeps the element in tab flow with other elements with an unspecified tab index which are still tabbable.)
If you separate the label from any field and set a tabIndex you can tab to it and capture mouse and key events. It seems more sensible to use buttons or inputs with type="button",
but suit yourself.
<form>
<fieldset>
<input value="today">
<label tabIndex="0" onfocus="alert('label');">Label 1</label>
</fieldset>
</form>
I have an alternative answer that I think has not been mentioned yet. For recent work I've been reading the Mozilla Developer Docs MDN Docs, Forms, especially the Accessibility Section MDN Docs, Accessible HTML(5), for information related to keyboard accessibility and form structure.
One of the specific mentions in the Accessibility section is to use HTML5 elements when and where possible -- they often have cross-browser and more accessible support by default (not always true, but clear content structure and proper elements also help screen reading along with keyboard accessibility).
Anyway, here's a JSFiddle: JSFiddle::Keyboard Accessible Forms
Essentially, what I did was:
shamelessly copy over some of the source code from a Mozilla source code to a JSFiddle (source in the comments of the fiddle)
create a TEXT-type and assign it the "readonly" HTML5 attribute
add attribute tabindex="0" to the readonly
Modify the "readonly" CSS for that input element so it looks "blank" or hidden"
HTML
<title>Native keyboard accessibility</title>
<body>
<h1>Native keyboard accessibility</h1>
<hr>
<h2>Links</h2>
<p>This is a link to Mozilla.</p>
<p>Another link, to the Mozilla Developer Network.</p>
<h2>Buttons</h2>
<p>
<button data-message="This is from the first button">Click me!</button>
<button data-message="This is from the second button">Click me too!
</button>
<button data-message="This is from the third button">And me!</button>
</p>
<!-- "Invisible" HTML(5) element -->
<!-- * a READONLY text-input with modified CSS... -->
<hr>
<label for="hidden-anchor">Hidden Anchor Point</label>
<input type="text" class="hidden-anchor" id="hidden-anchor" tabindex="0" readonly />
<hr>
<h2>Form</h2>
<form name="personal-info">
<fieldset>
<legend>Personal Info</legend>
<div>
<label for="name">Fill in your name:</label>
<input type="text" id="name" name="name">
</div>
<div>
<label for="age">Enter your age:</label>
<input type="text" id="age" name="age">
</div>
<div>
<label for="mood">Choose your mood:</label>
<select id="mood" name="mood">
<option>Happy</option>
<option>Sad</option>
<option>Angry</option>
<option>Worried</option>
</select>
</div>
</fieldset>
</form>
<script>
var buttons = document.querySelectorAll('button');
for(var i = 0; i < buttons.length; i++) {
addHandler(buttons[i]);
}
function addHandler(button) {
button.addEventListener('click', function(e) {
var message = e.target.getAttribute('data-message');
alert(message);
})
}
</script>
</body>
CSS Styling
input {
margin-bottom: 10px;
}
button {
margin-right: 10px;
}
a:hover, input:hover, button:hover, select:hover,
a:focus, input:focus, button:focus, select:focus {
font-weight: bold;
}
.hidden-anchor {
border: none;
background: transparent!important;
}
.hidden-anchor:focus {
border: 1px solid #f6b73c;
}
BTW, you can edit the CSS rule for .hidden-anchor:focus to remove the highlight for the hidden anchor if you want. I added it just to "prove" the concept here, but it still works invisibly as requested.
I hope this helps!
My preference:
.tab-only:not(:focus) {
position: fixed;
left: -999999px;
}
<button class="tab-only">Jump to main</button>
Another great option would be to nest your input + div in a label and hide the input by setting width and height to 0px instead of display: none
This method even allows you to use pseudo-classes like :focus or :checked by using input:pseudo + styleDiv
<label>
<input type="radio">
<div class="styleDiv">Display text</div>
</label>
input
{
width: 0px;
height: 0px;
}
input + .styleDiv
{
//Radiobutton style here
display: inline-block
}
input:checked + .styleDiv
{
//Checked style here
}
Discard the radio-buttons and instead; keep some hidden fields in your code, in which you store the selected value of your UI components.