Recently I posed a question, asking why some of my javascript code was misbehaving. However, the accepted answer didn't fully solve my problem, so here I am once again.
Problem Description
I have a <div> which has a collection of radio buttons in it.
I use jquery ui to style that collection with a buttonset(). It looks resonably pretty.
Then I empty the <div> with jquery by doing something to the effect of $("#mydiv").html("")
Then I once again restore exact contents that were removed.
Finally the buttonset is no longer working properly, because its events got unhinged in the process.
So my question is how to protect such bound events from being garbage collected, when I temporarily tinker with the DOM?
NB! I can't do display:none to hide the <div> instead, because the whole business with deleting html content and restoring it later is handled by an unnamed jquery plugin. Nor can I call buttonset() again, because a) the graphic style gets messed up, and b) there are other controls in my real problem that don't have this handy functionality. So what I really need is some way to protect all those handlers while the elements which behavior they are supposed to govern are temporarily missing from the DOM.
Sample Code
HTML
<div id="container">
<div id="buttonset">
<input type="radio" id="radio1" name="option" />
<label for="radio1">X</label>
<input type="radio" id="radio2" name="option" />
<label for="radio2">Y</label>
<input type="radio" id="radio3" name="option" />
<label for="radio3">Z</label>
</div>
</div>
<div id="control">
<input id="toggle" type="checkbox"/>
<label for="toggle">Toggle</label>
</div>
Javascript
$(function(){
$("#buttonset").buttonset();
$("#toggle").click(
function(){
if($(this).is(":checked"))
{
backup = $("#container").html();
$("#container").html("");
} else $("#container").html(backup);
}
)
});
Playable Version
See this jsFiddle
Solution
I used the idea in the accepted answer to save html contents before applying buttonset(), then reapply buttonset() each time as needed on that saved data.
Update:
Here's an updated fiddle that's pretty close to what your OP is. The basic idea is it destroys the buttonset to get the original html back
$(function() {
//Turn the radio buttons into a jquery ui buttonset
$("#buttonset").buttonset();
//Use the toggle button to hide/show the #container div.
//NB! It's not possible to do css display:none instead,
//due to some other limitations, to wit, I'm using a
//library that I can not modify.
$("#toggle").button();
var backup; // added this to prevent it from leaking onto global scope.
$("#toggle").click(function() {
if ($(this).is(":checked")) {
// restore the html back
$("#buttonset").buttonset("destroy");
backup = $("#container").html();
$("#container").html("");
}
else {
$("#container").html(backup);
$("#buttonset").buttonset();
}
})
});
Related
I think that my problem isn't very hard -but I'm pretty new to this and having issues finding an easy solution.
I have a form that collects a few items, and an output page that creates a table based on those few items. For example, one of the form options is "Which leg is affected?" And you must choose either "Left, Right, Both".
I would like to create a radio selection option on the view so that the person using this tool won't have to click the back button to update this one field. The table that is built changes based on this one selection, so it would be nice to see those changes without resubmitting the form.
If anyone can point me in the right direction - either JavaScript or some method that involves re-sending the form values from the view - I would be very grateful.
I believe what you're describing is exactly what the idea of "single page app" style coding with Javascript is for - modifying the page with logic without necessarily needing to make a server request. I.e., you want to make an "application." Albeit a simple one.
What I recommend you look into is "event handlers," specifically the click handler.
So, if you had html that looked like: (stolen from MDN's radio page)
<form id="radio_form">
<p>Please select your preferred contact method:</p>
<div>
<input type="radio" id="contactChoice1"
name="contact" value="email">
<label for="contactChoice1">Email</label>
<input type="radio" id="contactChoice2"
name="contact" value="phone">
<label for="contactChoice2">Phone</label>
<input type="radio" id="contactChoice3"
name="contact" value="mail">
<label for="contactChoice3">Mail</label>
</div>
</form>
You could then have code that looked like
var radio = document.getElementById('radio_form');
radio.onclick = changeTable;
function changeTable(e){
// Do logic here to change table
}
The idea is your page is "waiting" for the form to be "clicked" (you could also look into onChange), and when it is clicked, a function is invoked that does further logic.
See here to figure out how to get the value of a selected radio.
See here for using javascript to insert a row into a table (what you may want to do in your changeTable function).
EDIT: One "gotcha" to look out for is if your script is running when the page is actually loaded. This can be a problem if your page loads asynchronously (doubtful). Just in case, also look into some kind of document.ready implementation: Pure JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it
You can add an event listener for 'click' to each radio input and have the callback function modify the view in whatever way you want.
Here's an example:
const form = document.querySelector('.choice-form');
const display = document.querySelector('.display');
form.querySelectorAll('input[type="radio"]').forEach(input => {
input.addEventListener('click', () => {
display.innerHTML = "";
if (input.id === '1') {
display.innerHTML = "<span>You selected: <span class='red'>One</span></span>";
} else if (input.id === '2') {
display.innerHTML = "<span>You selected: <span class='blue'>Two</span></span>";
}
});
});
.red {
color: red;
}
.blue {
color: blue;
}
<div>
<form class='choice-form'>
<label for='choice'>Make a choice</label>
<input type='radio' id='1' name='choice'/>
<label for='1'>One</label>
<input type='radio' id='2' name='choice'/>
<label for='2'>Two</label>
</form>
<div class='display'>
</div>
</div>
I have a pretty simple query here. I have a view page with an div and a form element. This is how they look.
<div id="candy" value="valueOfCandy" ></div>
<input type="text" value="javascript:document.getElementById('candy').getAttribute('value')"/>
I need to access the value of candy inside input's attribute (it can be any attribute).
I tried the code as I have shown above but that didnt work. I researched on StackOverflow too but couldnt find anything satisfactory. Please help out.
Edit: Thank you everyone. I found the answer to that, which I am gonna mark. Also, deleting this question so that it doesnt confuse someone else.
If I assume you want to do this at page load, do it like this
Note 1, custom attributes should have a data- prefix and use .dataset to access its value.
Note 2, for older browsers like IE10 and below, you need getAttribute (as in 2nd sample below).
Stack snippet 1
<div id="candy" data-value="valueOfCandy"></div>
<input id="candy2" type="text" value="" />
<script>
document.getElementById('candy2').value =
document.getElementById('candy').dataset.value
</script>
Stack snippet 2
<div id="candy" data-value="valueOfCandy"></div>
<input id="candy2" type="text" value="" />
<script>
document.getElementById('candy2').value =
document.getElementById('candy').getAttribute('data-value')
</script>
Do it in JavaScript outside of code but after the objects exist.
Here's an example of how to achieve this:
var candy = document.getElementById('candy').getAttribute('data-value');
document.getElementById('input').value = candy;
<div id="candy" data-value="valueOfCandy" ></div>
<input id="input" type="text"/>
As mentioned in the comments, please make sure your JavaScript code is loaded after your markup. There are various ways to do this, including waiting for the dom to load.
See $(document).ready equivalent without jQuery and How does the location of a script tag in a page affect a JavaScript function that is defined in it? for more information.
Try this
document.getElementById('input').value = document.getElementById('candy').dataset.value
<div id="candy" data-value="valueOfCandy" ></div>
<input id="input" type="text" value=""/>
This is not how you should be doing this.
JavaScript should be separated out of the HTML completely to avoid a whole host of issues. Including JavaScript in the HTML as you are attempting is a 20+ year old technique that was used before we had standards.
Next, a div element can't have a value attribute. value is only for form fields. But, you can create a data-* attribute, which allows for you to create custom attributes. You can then extract that value using the .dataset property.
See below:
// This code would be placed inside of <script> and </script> tags and the whole
// thing would be placed just before the closing body tag (</body>).
document.getElementById("result").value = document.getElementById('candy').dataset.value;
<div id="candy" data-value="valueOfCandy"></div>
<input type="text" id="result">
Put that code either within a script tag or in a separated js file.
Further, always bind the event DOMContentLoaded when you need to manipulate DOM elements.
DOMContentLoaded
The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly popular mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious.
This way, your logic is totally consistent.
document.addEventListener("DOMContentLoaded", function(event) {
console.log("DOM fully loaded and parsed");
document.getElementById('candy2').value =
document.getElementById('candy').getAttribute('value')
});
<div id="candy" value="valueOfCandy"></div>
<input id="candy2" type="text" value="" />
A recommendation is to use data-attributes because the value attribute is related to form fields:
document.addEventListener("DOMContentLoaded", function(event) {
console.log("DOM fully loaded and parsed");
document.getElementById('candy2').value =
document.getElementById('candy').dataset.value;
});
<div id="candy" data-value="valueOfCandy"></div>
<input id="candy2" type="text" value="" />
Slightly odd question, but I'm trying to find a way (if possible) to select all radio buttons that have the same value. We regularly get hundreds of spam accounts signing up on our website, and it would be easier to set all radio buttons to "Reject" and double-check to make sure there's no legitimate ones, as opposed to constantly clicking on a radio button. (Lazy is my middle name, yes.)
Is this possible? If so, how? I haven't got access to the actual web pages to code in a button to do just this yet, but it's something I'm looking at long term. Right now though, I need something quick and dirty to do what I want it to do. I'm using Chrome, and can use Greasemonkey if that's required.
The value to select by is "reject".
A snippet of code that's being used. If it's of any consequence, our forum is running Xenforo:
<li>
<label for="ctrl_users16667action_reject">
<input type="radio" name="users[16667][action]" value="reject" class="Disabler" id="ctrl_users16667action_reject">
Reject and delete with rejection reason:
</label>
<ul id="ctrl_users16667action_reject_Disabler" class="disablerList">
<li>
<input type="text" name="users[16667][reject_reason]" value="" size="45" placeholder="Optional" class="textCtrl" id="ctrl_users16667reject_reason">
</li>
</ul>
</li>
You're looking for a bookmarklet or a GreaseMonkey (or TamperMonkey or similar) script.
Re bookmarklets, you can use the javascript: pseuedo-protocol to run script on the page you're looking at from your bookmarks manager. Just make the URL in your bookmark:
javascript:(function() { /* ...your code here ...*/ })();
Because it has to be URI-encoded, you can find "bookmarklet generators" out there to handle that part for you.
Alternately, there are GreaseMonkey, TamperMonkey, and similar add-ons/extensions for browsers.
Then it's a trivial matter of selecting the relevant radio buttons:
$('input[type=radio][value="reject"]').prop('checked', true);
So if jQuery is already loaded on the page in question, you could use this as a bookmarklet:
javascript:(function(){$('input[type=radio][value="reject"]').prop('checked',true);})();
Use :radio to get radio buttons, then for filtering use attribute equals selector
var $ele = $(':radio[value="reject"]')
or filter()
var $ele = $(':radio').filter(function(){ return this.value == 'reject'; });
FYI : It's a jQuery solution and it only works if you are loaded jQuery library in the page.
Try this it will work
$("input:radio[value=reject]")
you have to give unique name to all radio buttons then you can select multiple radio buttons using javascript
you have to give same class to radio button
<input type="radio" name="radio[]" class="my_class" value="1" />
<input type="radio" name="radio[]" class="my_class" value="1" />
<input type="radio" name="radio[]" class="my_class" value="0" />
$(".my_class").each(function(){
if($(this).val() == "1"){
$(this).attr('checked','checked);
}
});
Thanks
I have a server control which has a couple of radio buttons on it. I run a startup javascript script file which applied the JQuery UI buttonset() on them.
$(document).ready(function () {
$('#radiobuttonpanelid%').buttonset();
});
Everything works perfectly when outside of an UpdatePanel. If the server control is inside an update panel, no matter what I try, i get "Error: Object doesn't support property or method 'buttonset'". I get this message even the first time I open the page.
Update:
Rendered HTML when inside of the update panel looks like this:
<DIV>
<SPAN>
<INPUT name=ct1 id=ct1 type=radio CHECKED value=1>
<LABEL for=ct1>1</LABEL>
</SPAN>
<BR>
</DIV>
<DIV>
<SPAN>
<INPUT name=ct2 id=ct2 type=radio value=2>
<LABEL for=ct2>2</LABEL>
</SPAN>
<BR>
</DIV>
Anyone came across this issue?
I am using this plugin to customize check boxes and radio buttons on a page.
These radio buttons are in a div#Main element which comprise of some other HTML elements also. I need to disable everything in this div on a button click (I am using jQuery). For this I have the following code,
HTML
<input type="button" id="DisableElements" value="Disable elements" />
<div id="Main">
<input type="radio" class="styled" name="reg-all"/>
<input type="radio" class="styled" name="reg-all"/>
<select id="MyList">
<option value="1">Choice-1</option>
<option value="2">Choice-2</option>
</select>
<textarea id="Comments" rows="4" cols="5"></textarea>
</div>
Script
$(function(){
$('#DisableElements').click(function(){
$('#Main').find('*').attr('disabled', 'disabled');
});
});
Issue: Everything got disabled correctly except the radio buttons.
Behind the scenes, the plugin script hides the actual radio button and
put a span over the radio buttons like a blanket. This span has
got a background image sprite with different states (on and off) which
gets updated accordingly on radio button selection. This was the
working of this plugin.
I could have used the inbuilt method of the plugin to disable/destroy the functionality but I did not find any method for this.
images loads with little delay after the DOM has finished loading,
so you can try calling your function in $(window).load().
hope it will help.
The solution i made can be thought of as a patch but works nice (for my scenario at least). What should have been the right approach for this would be using some existing API method to reflect the change, something like disable() or similar but i did not find such method or something like this.
Solution: Making the radio buttons appear like disable (non clickable).
Because i do not want to dig into the plugin js file. For this i made a transparent div with some width and height enough to cover the radio buttons and place it over them like a layer between radio buttons and cursor. This div is hidden by default and show this while making controls disable. keeping it short and sweet, here are the code changes.
HTML
<input type="button" id="DisableElements" value="Disable elements" />
<div id="Main">
<div id="Blanket"></div>
<input type="radio" class="styled" name="reg-all"/>
<input type="radio" class="styled" name="reg-all"/>
<select id="MyList">
<option value="1">Choice-1</option>
<option value="2">Choice-2</option>
</select>
<textarea id="Comments" rows="4" cols="5"></textarea>
</div>
CSS - for blanket div
#Blanket
{
position:absolute; /*Imp: otherwise it will disturb the UI*/
width:100px;
height:100px;
display:none;
/* top/left adjustments, if required! */
}
Script
$(function(){
$('#DisableElements').click(function(){
$('#Blanket').show();
$('#Main').find('*').attr('disabled', 'disabled');
});
});
This solution however needed to drop the fear of what if someone using developer tools to out smart the application but that does not matter any way. Besides, you can-not 100% block the user from using such tools.
Another solution which worked and looks more appropriate: Placing invisible blanket over input controls sounds like a patch and can be easily snapped. The plugin script adds a CSS class named styled and requires to add following styles to achieve customized look and feel.
input.styled
{
display: none; // hides the parent input element
}
Because of this, even if we switch button states to disable, the changes did not reflect because the parent element was hidden making the other listeners difficult to attach. By changing the styles to following, everything worked.
input.styled
{
position: absolute;
opacity: 0;
}
It makes the parent input element invisible but completely active on DOM behind the scenes.