How to entirely disable/enable html elements? - javascript

I have several elements on the page. Something like:
<div id="el1"><div id="el2"><span id="el3">1</span><span id="el4">2</span></div><span id="el5">3</span></div>
I need to disable/enable any of them, using their ids.
<input type="radio" name="do" onclick="disable(document.getElementById('el4'));">
<input type="radio" name="do" onclick="enable(document.getElementById('el4'));">
What should be in disable() and enable() functions to really disable elements?
By "disable" I mean make it invisible for user, inaccessible by "id" and be restorable by "enable()" function.
Is it possible to turn elements on/off? Entirely, I mean.

function addEl4(){
var elem = document.getElementById('el2');
var newElem = document.createElement('div');
newElem.setAttribute('id', 'el4');
newElem.innerHTML = 2;
elem.appendChild(newElem);
};
function disable(elem){
var container = document.getElementById('el2');
container.removeChild(elem);
};
If you are talking in terms of removing the element from the page completely.
Then you can use the .removeChild() method..
Then need to append it to the div you are talking about..
Check Fiddle

You may use
document.getElementById('el4').style.display='none'; // hide
document.getElementById('el4').style.display=''; // show
You could define functions like this :
function hide(element){
element.style.display='none';
}
function show(element){
element.style.display='';
}
I really suggest not to use the enable and disable words, as they have other meanings (a disabled widget is one you can see but you can't change).
A better solution would be to define a css class
.hidden {
display: none;
}
and change the class in js :
document.getElementById('el4').classname='hidden'; // hide
If you want to completely remove an element, you may use removeChild :
var node = document.getElementById('el4');
node.parentNode.removeChild(node);
but it's almost never useful. Prefer to hide as is commonly done.

Related

Building a catch-all function for rendering

I am currently trying to render a calendar that uses checkboxes as filtering. I have all the filters working if I do it this way:
//Call my render event on click of a checkbox
$('.filterable-content__criteria').on('change', function(){
$('#calendar').fullCalendar('rerenderEvents');
});
This works so everytime I click a checkbox, it re-renders my calendar - thus showing/hiding events. Right now I am doing this relatively staticly where in my render function I do this:
var eventAcceptedClasses = [];
if ($('input#Event-Type-2').is(':checked')){
eventAcceptedClasses.push(id);
displayEvent = false;
} else if ($('input#Event-Type-2').is(':checked')){
eventAcceptedClasses.push('Event-Type-2');
displayEvent = false;
} else if ($('input#Event-Type-3').is(':checked')){
eventAcceptedClasses.push('Event-Type-3');
displayEvent = false;
} else {
//If none checked, show all.
eventAcceptedClasses.push('fc-event');
displayEvent = true;
};
This function is regrettably, not scalable. I'm looking to make it so on render, it takes the id of the checkbox that was clicked, then plugs it into the function ie: You set the id in the click event like this
var cb_click = event.target.id
Then my render just looks like this:
var eventAcceptedClasses = [];
if ($('input#'+cb_click ).is(':checked')){
eventAcceptedClasses.push(cb_click);
displayEvent = false;
}
But given the way the functions are nested, this doesn't seem to work due to the structure of the code.
Any ideas on how I can do this? I included a JS Fiddle that shows the full structure for clarification.
Edit:
Basic Input Structure
<input class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1" id="Event-Type-1">
If you can modify the html, adding an onchange attribute to your input is the way to go.
It is much simpler to understand, and is better for memory usage than an event listener, or a redundant testing if else.
In a short example, with just javascript, to call a function that pass the id of the current clicked element.
//Call my render event on click of a checkbox
function call_render(me){
console.log(me)
/* eventType1 */
// me.fullCalendar('rerenderEvents');
}
Tick: <input onchange="call_render(this.id)" id="eventType1" class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1">
Sometimes we just can't modify the html from the source.
The html can also become a bit unreadable when too much attributes are set.
It is also not so good for fixing stuffs and readability when javascript is written inside html attribute, like in the previous example.
Attributes needs to be set at the DOM level. It is better practice. There is alternatives, but it's always better to use html capabilities first.
// DOM now ready
// Set the onchange attribute to the element *eventType1*.
// And give this attribute a function when a change happen
eventType1.setAttribute("onchange","call_render(this.id)")
//Call my render event on click of a checkbox
function call_render(me){
console.log(me)
/* eventType1 */
// me.fullCalendar('rerenderEvents');
}
Tick: <input class="filterable-content__criteria" type="checkbox" name="categories" value="Event Type 1" id="eventType1">
To verify or test the checkbox state:
console.log( (eventType1.checked) )
console.log( !(eventType1.checked) )
Tick: <input id="eventType1" type="checkbox" checked="">
Again, we can also set a global event handler like this:
eventType1.oninput = (function() {
call_render(this.id)
})
Js perf test, to compare the 3 methods.
I removed the querySelector, the inline onchange is stil faster.
https://jsperf.com/global-vs-event-vs-inline

How can I invisiblize groups of controls via jQuery?

In my Sharepoint project/Web Part/Web Page, I dynamically create page elements/controls using C# in the *.ascx.cs file.
In the *.ascx file, I use jQuery for responding to events that happen on the page (selections, changes of checkbox states, etc.).
I have a need to conditionally invisiblize groups of controls/elements on the page. Specifically, if the user checks a certain checkbox, I can "remove" whole swaths of the page that, in that scenario, don't apply to her.
How can I do this? I've got this starting point:
/* If the select "Yes" (they are seeking payment for themselves, as opposed to someone else), omit (invisibilize) sections 2 and 3 on the form */
$(document).on("change", '[id$=ckbxPaymentForSelf]', function () {
var ckd = this.checked;
if (ckd) {
// what now?
}
});
I could do it the hair-pulling-out way (which would be very painful for me, because I have almost as much hair as Absalom did), and set each individual element, like so:
if (ckd) {
var $this = $('[id$=txtbxthis]');
var $that = $('[id$=txtbxthat]');
var $theother = $('[id$=txtbxtheother]');
. . . // store a reference to all the other to-be-affected elements in vars
$this.visible = false; // <= this is pseudoscript; I don't know what the jQuery to invisiblize an element is
$that.visible = false; // " "
$theother.visible = false; // " "
. . . // invisiblize all the other to-be-affected elements
}
Surely there's a more elegant/better way!
Is it a matter of assigning all the conditionally invisible elements a particular class, and then invisiblizing every element that is assigned that class, or what?
Also, I want the area formerly used by this now-invisible swath to "go away" or "roll up" not sit there with a blank stare, yawning chasm, or Gobi Desert-like featureless expanse.
there are a number of ways to do this. but in your jquery implementation I would decorate the elements with data tags that will tell the code which elements to hide and show.
<input data-group="1" type="text" />
<input data-group="2" type="text" />
var $group1 = $('*[data-group="1"]');
var $group2 = $('*[data-group="2"]');
if (ckd) {
$group1.hide();
$group2.show();
}
else{
$group2.hide();
$group1.show();
}
You could do the same thing with css classes as well but I prefer using the data attribute
If you can group your controls using classes, you could select the class which needs to be hidden in that particular scenario and just use the hide() function:
if (ckd) {
var cls = getClassForCurrentScenario();
$("." + cls).hide(); //slideUp() would be an animated alternative
}
If the controls can be grouped inside a div, for example, then you'd just need to hide that element:
if (ckd) {
var id = getElementIdForCurrentScenario();
$("#" + id).hide(); //slideUp() would be an animated alternative
}
It really depends on how you manage to group your controls into "target groups", so that you can efficiently access them later.
You can hide an element like so:
$('...').hide();
Or you can slide it up with:
$('...').slideUp();
to get a nice sliding up animation.
On a side note, you can do this to multiple elements at once, in your case:
$('[id$=txtbxthis], [id$=txtbxthat], [id$=txtbxtheother]').slideUp();

How Can I Rewrite This More Efficiently

I have to believe that there's a better way to write the below code. Thanks in advance.
var hProtein = $('#protein-lbl');
var hCarb = $('#carb-lbl');
var hFat = $('#fat-lbl');
var hTotal = $('#totalCalories');
// Normal Calc vars
var nProtein = $('#protein-normal-lbl');
var nCarb = $('#carb-normal-lbl');
var nFat = $('#fat-normal-lbl');
var nTotal = $('#totalCalories-normal');
// Hide calculations until bodyweight is entered
hProtein.hide();
hCarb.hide();
hFat.hide();
hTotal.hide();
nProtein.hide();
nCarb.hide();
nFat.hide();
nTotal.hide();
Perhaps giving the HTML elements a class will work?
var $ele = $('.class-name');
$ele.hide();
The best solution is to have the default condition of the page specified in HTML/CSS, so it displays properly at first and you don't have to run a bunch of javascript just to set up the default condition.
So, if what you're trying to do is establish the default condition upon page load, change the display style of all these elements to style="display: none;" right in the HTML so they start out with the right state.
Or better yet, give them all a common class name and create a CSS style rule so they are all initially hidden. Doing this in the markup/CSS will prevent them showing and then hiding as your script runs - they will just start out with the right state.
CSS:
.initialHidden {
display: none;
}
HTML:
<div id="totalCalories-normal" class="initialHidden"></div>
add common class to element the hide it by this way
$('.common-class-name').hide()
OR
Put all elements in Single div wrap and hide it by that id
I would do this :
$([
'#protein-lbl',
'#carb-lbl',
'#fat-lbl',
'#totalCalories',
'#protein-normal-lbl',
'#carb-normal-lbl',
'#fat-normal-lbl',
'#totalCalories-normal'
].join()).hide();
Why not wrap the labels in a fieldset and hide the fieldset

Toggle effect problem when using for-loop in IE7

I'm a webdesigner that's trying to get the hang of JavaScript and jQuery, and I want to learn how to write shorter, more concise code - to avoid being ridiculed by the developers at work ;)
I have this snippet:
// toggle divs when checkbox is checked
$('.product-optional-checkbox1').click(function () {
$('.product-optional-toggle1').toggle('fast');
});
$('.product-optional-checkbox2').click(function () {
$('.product-optional-toggle2').toggle('fast');
});
$('.product-optional-checkbox3').click(function () {
$('.product-optional-toggle3').toggle('fast');
});
// hide divs
$('.product-optional-toggle1').hide();
$('.product-optional-toggle2').hide();
$('.product-optional-toggle3').hide();
...that I want to reduce using a for-loop, like this:
for( var i = 1; i < 4; ++i ) {
$('.product-optional-checkbox' + i).click(function () {
$(this).parent('div').find('div').toggle('fast');
});
$('.product-optional-toggle' + i).css({ display: 'none'});
};
It works fine in FF, however in IE7 it toggles twice. Anyone know who to solve a problem like this?
It's hard to say without seeing the HTML structure but maybe going to the parent then descendants is finding multiple divs?
In your example, you could replace:
$(this).parent('div').find('div').toggle('fast');
With code more similar to the original examples:
$('.product-optional-toggle' + i).toggle('fast');
However, it would be much better to ditch all the numbers and just use a class of .product-optional-checkbox. This way you can add a click function to all elements of that class in one go and avoid the loop:
$('.product-optional-checkbox').click(function () {
// do stuff using $(this)
});
Given that your click events seem to be tied to checkboxes (based on the class names you have in your example), why not actually provide code to handle click events for those checkboxes? For example:
<div id='my_group_of_checkboxes'>
<input type="checkbox" id="checkbox1">
<input type="checkbox" id="checkbox2">
...
</div>
And your jQuery code is then stripped down to three lines:
$('#my_group_of_checkboxes :checkbox').click(function(){
$(this).parent('div').hide('fast');
});
You also seem to need to hide the <div> elements related to each checkbox:
$('div[class^="product-optional"]').hide();
Although ID selectors would be a better option here and, depending on their position within your page, you may even be able to get away with something like:
$('#my_container_div_id div').hide();
If you can post some of your HTML, that might help provide more accurate answers as well.

How can I create an element that flips between two values on click?

Given two spans like this:
<span>Click for info</span>
<span style="display: none">Here is a big long string of info blah blah</span>
...I'd like to have an onclick function attached to each so that the visitor sees "Click for info", and then when they click it, the first span is hidden and the second is unhidden. And, of course, when the second is clicked, things go back to the way they were originally.
I don't have a way of easily generating unique IDs, so I'd prefer to avoid the getElementByID() route, and I'd rather not use jQuery or any other heavyweight dependency. Is there an elegant way to do this?
The best idea I have so far is to write a toggleAllSiblings() function, set onclick to that function for both elements in the pair, and then wrap each pair in a parent element.
Can it be done without the parent node?
If you really want to go without ids you could do something like this:
<script>
function togglePrevious(sender) {
sender.previousSibling.style.display = "inline";
sender.style.display = "none";
}
function toggleNext(sender) {
sender.nextSibling.style.display = "inline";
sender.style.display = "none";
}
</script>
<span onclick="javascript:toggleNext(this);">Click for info</span>
<span onclick="javascript:togglePrevious(this);" style="display:none">Info blablabla</span>
And please not that you should really use "inline" instead of "block" if you are using spans as they are inline elements. Setting their display style to block will force them to be divs.
Yet another version, a la progressive enhancement — will properly show the full info when JavaScript is off.
<span class="details">Here is a big long string of info blah blah</span>
<script type="text/javascript">
// Open/close span behaviour
//
function infoToggle(span) {
var ersatz= document.createElement('span');
ersatz.appendChild(document.createTextNode('Click for info...'));
span.parentNode.insertBefore(ersatz, span);
span.style.display= 'none';
span.onclick= function() {
ersatz.style.display= 'inline';
span.style.display= 'none';
};
ersatz.onclick= function() {
ersatz.style.display= 'none';
span.style.display= 'inline';
};
}
// Bind to all spans with class="details"
//
var spans= document.getElementsByTagName('span');
for (var i= spans.length; i-->0;)
if (spans[i].className=='details')
infoToggle(spans[i]);
</script>
I'm not sure of the implementation, but the logic will look similiar to
Get all spans
Hide adjacent spans
beneath (leave them visible for non
JS users by default)
Attach even
handler to first spans
Event handler
function - show next span if next
span invisible, otherwise hide it
This is off the top of my head & untested. It should get you going at least.
<script>
function toggle(id)
{
var display = document.getElementById(id).style.display;
if ( display == "block" )
document.getElementById(id).style.display = "none";
else
document.getElementById(id).style.display = "block";
}
</script>
<span onclick="javascript: toggle('span_to_toggle');" id="clickable_span">click here</span>
<span id='span_to_toggle' style="diplay:none">foooooooooooooooooooooo</span>
quick rework of #Jason:
<script>
function toggle(targetId, sender)
{
var show = document.getElementById(targetId);
show.style.display = "block";
sender.style.display = "none";
}
</script>
<span onclick="javascript: toggle('more', this);" id="less">click here</span>
<span style="display:none;" id="more" onclick="javascript: toggle('less', this);" >foooooooooooooooooooooo</span>
Just as a side note for when you're developing javascript stuff which involves creating elements in the DOM. If you're not going to use something like jQuery (I'm not a fan of frameworks, too heavy and non-specific) try and use a function to make your elements for you, that way you don't have too many redundant lines as it tends to make your scripts really heavy.
I personally use a code snippet i found here www.dev-explorer.com/articles/create-dom-object but you might find something that suits you better. If your site downloads quicker the user doesn't have to wait as long for onload events etc and generally doesn't get annoyed as easily.
Hope this made sense
Thanks,
Scarlet
I'd rather not use jQuery or any other heavyweight dependency.
I don't know if that is a good approach. Unless you can attribute any real performance problem to using jQuery or prototype.js (which are both not really that heavy), you should use them.
Otherwise you will just spend a lot of time with repetitive typing and on fixing nasty browser bugs and incompatibilites.
I don't have a way of easily generating unique IDs
Again, you really want $$('div span[someParam=something]'). And since the libraries dispatch this to native browser query functions where available, it is probably not even slower than a hand-coded solution. Definitely more maintainable.

Categories

Resources