JavaScript How to use "this" with onchange event and select element - javascript

I have got several select tags and divs in my html:
<div>
<select name="one" id="oneId" class="selectOne" onchange="myFunction()">
<option value="" disabled selected>choose*</option>
<option value="1">Yes</option>
<option value="2">No</option>
</select>
<div class="show" style="display:none;">
<input type="number" value="" id="other"></input>
</div>
</div>
Now I would like to do semething like this:
function myFunction() {
var a = this.value; // to select this "select tag" of this function
var b = this.closest("show"); // to select closest "show div" to select tag
var c = b.children; //input // to select input in "show div"
if (a == 1) {
b.style.display = "block";
c.removeAttribute("disabled");
} else {
b.style.display = "none";
c.setAttribute('disabled','disabled');
}
}
function myFunction() {
var a = this.value; // to select this "select tag" of this function
var b = this.closest("show"); // to select closest "show div" to select tag
var c = b.children; //input // to select input in "show div"
if (a == 1) {
b.style.display = "block";
c.removeAttribute("disabled");
} else {
b.style.display = "none";
c.setAttribute('disabled', 'disabled');
}
}
<div>
<select name="one" id="oneId" class="selectOne" onchange="myFunction()">
<option value="" disabled selected>choose*</option>
<option value="1">Yes</option>
<option value="2">No</option>
</select>
<div class="show" style="display:none;">
<input type="number" value="" id="other"></input>
</div>
</div>
The main problem is with selecting proper elements (read the comment tags)

Referencing the event target
this will differ depending on how the listener-function is added to an element.
You can add a listener using …
… EventTarget.addEventListener(). this will be the element it is added to.
… HTMLElement.onevent – where event of .onevent is an actual event name. this will be the element it is added to.
… inline onevent listeners (e.g. using the HTML-attribute onchange="myFunction()"). this will be the global object, see globalThis.
It is generally recommended to use EventTarget.addEventListener() for multiple reasons. Here are two of many reasons why you should use it:
It allows for multiple listeners to be added instead of just one.
Using it will keep your HTML clear of JavaScript, separating functionality from structure. Use JavaScript to add functionality, not HTML.
Here is an example demonstrating the ways of adding listeners:
document.querySelector('button').addEventListener('click', log); // Case 1
document.querySelector('button:nth-child(2)').onclick = log; // Case 2
function log() {
console.log((this === globalThis ? "'this' is 'globalThis'" : this));
}
<button>Using addEventListener()</button>
<button>Using Element.onclick</button>
<button onclick="log()">Using onevent-listener</button> <!-- Case 3 -->
To make it more consistent, one can use Event.target. The event-object is usually passed as the first argument. Using inline onevent listener would require you to pass the event-object event yourself.
Using Event.target will always return the event-target, regardless of what way you choose to add the listener.
The modified code would look like this:
document.querySelector('button').addEventListener('click', log); // Case 1
document.querySelector('button:nth-child(2)').onclick = log; // Case 2
function log(evt) {
console.log((evt.target === globalThis ? 'test' : evt.target));
}
<button>Using addEventListener()</button>
<button>Using Element.onclick</button>
<button onclick="log(event)">Using onevent-listener</button> <!-- Case 3 -->
Finding other elements relative to an element
This is accomplished by using the .querySelector() function of Element or Document to query for children, and the Element.closest() function to query for ancestors. Both functions require a String containing CSS selectors to be passed.
In case you need to find a neighboring sibling, you can use Node.nextSibling or Node.previousSibling to find neighboring Node siblings. This also includes TextNodes and similar non-element Nodes.
To only find neighboring element siblings, use Element.nextElementSibling or Element.previousElementSibling.
If your <div class="show"> will always be the following element after your <select>, you can simply use .nextElementSibling like this:
document.querySelector('select').addEventListener('change', selectChanged);
function selectChanged(evt) {
var divShow = evt.target.nextElementSibling;
divShow.style.display = evt.target.value;
}
<select>
<option disabled selected>Choose</option>
<option value="block">Show <div></option>
<option value="none">Hide <div></option>
</select>
<div class="show" style="display:none">
This <div> is shown.
</div>

this refers to the select element inside the onchange function.
You are calling myFunction() from that function so, as per the standard rules, this is going to be window inside myFunction.
If you want to pass the element along then you'll need to do so explicitly (either as an argument or with apply or call).
Better yet, don't use intrinsic event attributes (which have all sorts of issues), and use addEventListener instead.
Once you've sorted that problem, you'll find that you are using closest completely wrong.
It searches ancestors not siblings (so possibly you'd want this.parentElement.querySelector instead) and, like querySelector expects a selector and not a plain class name.

Related

jQuery .hide() and CSS display:none; are not working on <option> element in Safair 9.0.3 [duplicate]

This should work:
$('option').hide(); // hide options
It works in Firefox, but not Chrome (and probably not in IE, not tested).
A more interesting example:
<select>
<option class="hide">Hide me</option>
<option>visible option</option>
</select>
<script type="text/javascript">
// try to hide the first option
$('option.hide').hide();
// to select the first visible option
$('option:visible').first().attr('selected', 'selected');
</script>
Or see the example at http://jsfiddle.net/TGxUf/
Is the only option to detach the option elements from the DOM? I need to show them again later, so this would not be very effective.
Unfortunately, you can't hide option elements in all browsers.
In the past when I have needed to do this, I have set their disabled attribute, like so...
$('option').prop('disabled', true);
I've then used the hiding where it is supported in browsers using this piece of CSS...
select option[disabled] {
display: none;
}
As has been said, you can't display:none individual <option>s, because they're not the right kind of DOM elements.
You can set .prop('disabled', true), but this only grays out the elements and makes them unselectable -- they still take up space.
One solution I use is to .detach() the <select> into a global variable on page load, then add back only the <option>s you want on demand. Something like this (http://jsfiddle.net/mblase75/Afe2E/):
var $sel = $('#sel option').detach(); // global variable
$('a').on('click', function (e) {
e.preventDefault();
var c = 'name-of-class-to-show';
$('#sel').empty().append( $sel.filter('.'+c) );
});
At first I thought you'd have to .clone() the <option>s before appending them, but apparently not. The original global $sel is unaltered after the click code is run.
If you have an aversion to global variables, you could store the jQuery object containing the options as a .data() variable on the <select> element itself (http://jsfiddle.net/mblase75/nh5eW/):
$('#sel').data('options', $('#sel option').detach()); // data variable
$('a').on('click', function (e) {
e.preventDefault();
var $sel = $('#sel').data('options'), // jQuery object
c = 'name-of-class-to-show';
$('#sel').empty().append( $sel.filter('.'+c) );
});
Had a crack at it myself and this is what I came up with:
(function($){
$.fn.extend({detachOptions: function(o) {
var s = this;
return s.each(function(){
var d = s.data('selectOptions') || [];
s.find(o).each(function() {
d.push($(this).detach());
});
s.data('selectOptions', d);
});
}, attachOptions: function(o) {
var s = this;
return s.each(function(){
var d = s.data('selectOptions') || [];
for (var i in d) {
if (d[i].is(o)) {
s.append(d[i]);
console.log(d[i]);
// TODO: remove option from data array
}
}
});
}});
})(jQuery);
// example
$('select').detachOptions('.removeme');
$('.b').attachOptions('[value=1]');');
You can see the example at http://www.jsfiddle.net/g5YKh/
The option elements are fully removed from the selects and can be re-added again by jQuery selector.
Probably needs a bit of work and testing before it works well enough for all cases, but it's good enough for what I need.
I know this is a little late but better late than never! Here's a really simple way to achieve this. Simply have a show and hide function. The hide function will just append every option element to a predetermined (hidden) span tag (which should work for all browsers) and then the show function will just move that option element back into your select tag. ;)
function showOption(value){
$('#optionHolder option[value="'+value+'"]').appendTo('#selectID');
}
function hideOption(value){
$('select option[value="'+value+'"]').appendTo('#optionHolder');
}
Hiding an <option> element is not in the spec. But you can disable them, which should work cross-browser.
$('option.hide').prop('disabled', true);
http://www.w3.org/TR/html401/interact/forms.html#h-17.6
You can try wrapping the option elements inside a span so that they wont be visible but still be loaded in the DOM. Like below
jQ('#ddlDropdown option').wrap('<span>');
And unwrap the option which contains the 'selected' attribute as follows to display already selected option.
var selectedOption = jQ('#ddlDropdown').find("[selected]");
jQ(selectedOption).unwrap();
This works across all the browsers.
Here's an option that:
Works in all browsers
Preserves current selection when filtering
Preserves order of items when removing / restoring
No dirty hacks / invalid HTML
$('select').each(function(){
var $select = $(this);
$select.data('options', $select.find('option'));
});
function filter($select, search) {
var $prev = null;
var $options = $select.data('options');
search = search.trim().toLowerCase();
$options.each(function(){
var $option = $(this);
var optionText = $option.text();
if(search == "" || optionText.indexOf(search) >= 0) {
if ($option.parent().length) {
$prev = $option;
return;
}
if (!$prev) $select.prepend($option);
else $prev.after($option);
$prev = $option;
} else {
$option.remove();
}
});
}
JSFiddle: https://jsfiddle.net/derrh5tr/
On pure JS:
let select = document.getElementById("select_id")
let to_hide = select[select.selectedIndex];
to_hide.setAttribute('hidden', 'hidden');
to unhide just
to_hide.removeAttr('hidden');
or
to_hide.hidden = true; // to hide
to_hide.hidden = false; // to unhide
Three years late, but my Googling brought me here so hopefully my answer will be useful for someone else.
I just created a second option (which I hid with CSS) and used Javascript to move the s backwards and forwards between them.
<select multiple id="sel1">
<option class="set1">Blah</option>
</select>
<select multiple id="sel2" style="display:none">
<option class="set2">Bleh</option>
</select>
Something like that, and then something like this will move an item onto the list (i.e., make it visible). Obviously adapt the code as needed for your purpose.
$('#sel2 .set2').appendTo($('#sel1'))
It's possible if you keep in object and filter it in short way.
<select id="driver_id">
<option val="1" class="team_opion option_21">demo</option>
<option val="2" class="team_opion option_21">xyz</option>
<option val="3" class="team_opion option_31">ab</option>
</select>
-
team_id= 31;
var element = $("#driver_id");
originalElement = element.clone(); // keep original element, make it global
element.find('option').remove();
originalElement.find(".option_"+team_id).each(function() { // change find with your needs
element.append($(this)["0"].outerHTML); // append found options
});
https://jsfiddle.net/2djv7zgv/4/
This is an enhanced version of #NeverEndingLearner's answer:
full browsers support for not using unsupported CSS
reserve positions
no multiple wrappings
$("#hide").click(function(){
$("select>option.hide").wrap('<span>'); //no multiple wrappings
});
$("#show").click(function(){
$("select span option").unwrap(); //unwrap only wrapped
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<select>
<option class="hide">Hide me</option>
<option>visible option</option>
</select>
<button id="hide">hide</button>
<button id="show">show</button>
Since you mentioned that you want to re-add the options later, I would suggest that you load an array or object with the contents of the select box on page load - that way you always have a "master list" of the original select if you need to restore it.
I made a simple example that removes the first element in the select and then a restore button puts the select box back to it's original state:
http://jsfiddle.net/CZcvM/
Try this:
$(".hide").css("display","none");
But I think it doesn't make sense to hide it. if you wanna remove it, just:
$(".hide").remove();
just modify dave1010's code for my need
(function($){
$.fn.extend({hideOptions: function() {
var s = this;
return s.each(function(i,e) {
var d = $.data(e, 'disabledOptions') || [];
$(e).find("option[disabled=\"disabled\"]").each(function() {
d.push($(this).detach());
});
$.data(e, 'disabledOptions', d);
});
}, showOptions: function() {
var s = this;
return s.each(function(i,e) {
var d = $.data(e, 'disabledOptions') || [];
for (var i in d) {
$(e).append(d[i]);
}
});
}});
})(jQuery);
http://jsfiddle.net/AbzL3/1/
I thought I was bright ;-)
In CSS:
option:disabled {display:none;}
In Firefox and Chrome, a select with only the enabled options were created. Nice.
In IE, the enabled options were shown, the disabled where just blank lines, in their original location. Bad.
In Edge, the enabled options shown at top, followed by blank lines for disabled options. Acceptable.
document.getElementById('hide').style.visibility='hidden';
ive used id here for option

Passing selected dropdown value to query string in an anchor tag

How to pass the selected value from select tag to anchor tag as a query string so that it can be accessible on other php page?
I want to do something like this:
<select name="category">
<option></option>
</select>
<a href="category.php?selected='category.value'></a>
What is the right way to do that? I am using html and php.
Something like this?
$('[name="category"]').change(function(){
var href = $(this).val();
$('.linkhere').attr('href','category.php?selected='+href);
});
http://jsfiddle.net/gw8wk3vp/
Using plain JavaScript, I'd suggest:
// a named function to handle the change event:
function addValueToURL() {
// this (in this demo the <select> element) passed
// automatically from the addEventListener() method;
// here we encode the value of the <select> using
// encodeURIComponent() to ensure the value will
// be made up of URL-safe/valid characters:
var value = encodeURIComponent(this.value),
// getting a reference to the <a> element that you
// want to update:
anchor = this.nextElementSibling;
// the HTMLAnchorElement's search property,
// the portion of a URL following the '?'
// is here set to the string 'category='
// followed by the URI-encoded value from
// the <select>:
anchor.search = 'category=' + value;
}
// getting a reference to the first element that matches
// the CSS selector, selecting a <select> element with a
// name-attribute equal to 'category':
var select = document.querySelector('select[name=category]'),
// creating a new Event (with the same name as an
// existing event) in order to trigger that event
// when the page loads:
changeEvent = new Event('change');
// binding the function as the event-handler
// for the 'change' event:
select.addEventListener('change', addValueToURL);
// triggering the 'change' event:
select.dispatchEvent(changeEvent);
With the CSS:
a::before {
content: attr(href);
}
The CSS is entirely irrelevant to the functionality, it just allows you to see the changes in the URL of the <a> element as they happen.
function addValueToURL(event) {
var value = encodeURIComponent(this.value),
anchor = this.nextElementSibling;
anchor.search = 'category=' + value;
}
var select = document.querySelector('select[name=category]'),
changeEvent = new Event('change');
select.addEventListener('change', addValueToURL);
select.dispatchEvent(changeEvent);
a::before {
content: attr(href);
}
<select name="category">
<option value="option1">Option One</option>
<option value="option2">Option Two</option>
<option value="option3">Option Three</option>
<option value="option4">Option Four</option>
</select>
With regards to your comment elsewhere:
can we do this in simple html anchor tag without using [JavaScript]…
No, at least not currently
…or [jQuery]
Absolutely, yes; jQuery is never a requirement, it's simply a library of JavaScript which makes it easier to write simple cross-browser compatible code (the library handles the cross-browser problems transparently, so that the author doesn't have to worry about it).
References:
CSS:
CSS pseudo-elements.
JavaScript:
Creating and Triggering Events.
document.querySelector().
EventTarget.addEventListener().
EventTarget.dispatchEvent().
HTMLAnchorElement.
NonDocumentTypeChildNode.nextElementSibling.
HTMLSelectElement.

Using jQuery to show/hide html content only works if class is hard-coded

I have a series of hidden html form-groups that I want to display based on the values chosen in two cascading select lists. I'm using jQuery to toggle a class on the second list which is then called by an on change event function.
If I hard-code the class, the subsequent form-groups are shown when the on change is fired.
If I use the toggleClass from jQuery to dynamically change the class, the on change function doesn't fire even though the class is toggled correctly.
HTML
<div class="form-group hidden" id="option_env">
<label class="col-xs-12 col-sm-2 control-label" for="ddl_env">Options</label>
<div class="col-xs-12 col-sm-10">
<select name="category" id="ddl_env" class="form-control ">
<option value="-- Select an option --">-- Select an option --</option>
<option value="horse">Tethered horses</option>
<option value="Watercourses">Watercourses</option>
</select>
</div>
</div>
jQuery
var cascadeSelect = $('#ddlcategory');
var optionSelect = cascadeSelect.on('change', function () {
hideAll();
var option = $(this).val();
var childSelect = showOption(option);
return childSelect;
});
$('.option').on('change', function () {
hideDetail();
var detail = $(this).val();
showDetail(detail);
});
function showOption(option) {
var returnOption = null;
$('#' + option).toggleClass('chosen hidden')
.find('select').toggleClass('option')
;
var ddl_option = option.substr(option.indexOf('_')+1);
return returnOption = $('#ddl_' + ddl_option);
}
This works insofar as the ddl_env select has the option class added by the jQuery find, however, the $('.option').on('change', function () doesn't fire when the select list item is changed.
If I comment out the line .find('select').toggleClass('option') and manually add the option class to the ddl_env select then it works fine.
I get the same result with jQuery.addClass.
Debugging in Chrome shows that the ddl_env select change doesn't fire the change event when the option class isn't hard-coded.
Classic question.
Replace
$('.option').on('change', function()...
with
$(document).on('change', '.option', function()...
The second syntax works on present and future '.option' items.
This handler will only work on anything with the clas option when the page loads
$('.option').on('change', function () {
hideDetail();
var detail = $(this).val();
showDetail(detail);
});
In order for you to get it to work on elements dynamically allocated that class after the page has loadewd you need to delegate the event handler to a higher element, so basically its parent, or if all else fails document
$(document).on('change', '.option', function () {
hideDetail();
var detail = $(this).val();
showDetail(detail);
});

Use JQuery to get data from select multiple tab

I would like to use select multiple tab in html like
<select name="foo" multiple>
<option value="all">option1</option>
<option value="all">option2</option>
<option value="all">option3</option>
</select>
How can I get data in javascript from this multiple select tab
I tried
var foo = [];
$('#foo:selected').each(
function(i,selected) {
foo[i] = $(selected).text();
}
);
But no luck, it doesn't work. It shows foo.length==0
What is the correct way to do this? Thanks!
$('#foo:selected')
should be
$('#foo option:selected')
Selected attribute is a property of the options inside select and not select element.
Secondly you have no element with id="foo"
$('[name=foo] option:selected') // for this case
$('#foo:selected')
This tries to find instances of #foo which are selected. But that's the select element itself, not the options therein. Try with the options:
$('#foo option:selected')
Update: It looks like the first part of the selector is wrong, too. You don't actually have an element of id foo so #foo won't find anything. What you have is a select element with the name foo. So something like this instead:
$('select[name="foo"] option:selected')
Try this instead:
var foo = [];
$("[name='foo']").change(function () {
$("[name='foo'] option:selected").each(function (i, selected) {
foo[i] = $(this).text();
});
})
.trigger('change');

Converting jQuery code into Javascript

I am very new to Javascript and jQuery. I am trying to implements a dropdown select box, whereby, when certain items are selected an input text box is disabled. I was able to implement by hacking together some jQuery from various StackOverFlow questions:
<select name="Severity-of-your-symptoms" id="Severity-of-your-symptoms" class="cformselect" >
<option value="full01_severity_notselected" selected="selected">Please select...</option>
<option value="full01_severity_other">Mild</option>
<option value="full01_severity_other">Moderate</option>
<option value="Severe">Severe</option>
<option value="full01_severity_other">Other</option>
</select>
<br />
<input type="text" id="li-10-14" />
<input type="text" name="firstname" title="First Name" style="color:#888;"
value="First Name" onfocus="inputFocus(this)" onblur="inputBlur(this)" id='color'/>
<script type='text/javascript' src='http://code.jquery.com/jquery-1.4.2.js'></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.0/jquery-ui.js"></script>
<script type="text/javascript">
$('#Severity-of-your-symptoms').change(function() {
$("#li-10-14")[$(this).val() == "full01_severity_other" ? 'show' : 'hide']("fast");
}).change();
$('#Severity-of-your-symptoms').change(function() {
$("#li-10-14")[$(this).val() == "full01_severity_other" ? $('#color').attr("disabled", true)
: $('#color').attr("disabled", false)]
}).change();
</script>
I really wanted to implement this in Javascript but was only able to get it working with jQuery, can anyone help me convert this into pure Javascript?
If I understand the intent of your code, you can do it like this. The only thing this leaves out is animation for hiding/showing like you had with jQuery.
// this code should be located after the rest of the HTML at the end of the <body> tag
function checkSeverity() {
var displayVal, disabledVal;
if (document.getElementById("Severity-of-your-symptoms").value == "full01_severity_other") {
displayVal = "inline";
disabledVal = true;
} else {
displayVal = "none";
disabledVal = false;
}
document.getElementById("li-10-14").style.display = displayVal;
document.getElementById("color").disabled = disabledVal;
}
// hook up the event handler
document.getElementById("Severity-of-your-symptoms").onchange = checkSeverity;
// call it initially to establish the initial state
checkSeverity();
You can see it work here: http://jsfiddle.net/jfriend00/3xGxp/
Taking it in bits:
$('#Severity-of-your-symptoms')
The $ function creates a "jQuery object" that is an array with additional methods. The members of the array are the elements selected by the selector. In this case, it is using an ID so only one element is selected. It can be replaced by:
var element = document.getElementById('severity-of-your-symptoms');
.change(function(){...})
This calls a method of the jQuery object to add an onchange listener to the element what will be called when the element receives a change event. If you only need one change listener, then you can attach it to the onchange property:
element.onchange = function(){...};
But element might be null, so better to do:
if (element) element.onchange = function(){...};
To remove the jQuery bits from the function, if you just want the element to appear and dissaear, then:
function() {
var element = document.getElementById('li-10-14');
if (this.value == "full01_severity_other") {
element.style.display = element.style.display == 'none'? '' : 'none';
}
}
If you want fade in/out or slide up/down effects, there are very simple libraries to implement those.
Finally there is:
.change();
You could write the whole thing as a single statement, but I think it's much more robust to keep it as seperate statements. Converting the other part is much the same.

Categories