replace for loop with a switch statement somehow?
You don't have to loop over all radio buttons to find the clicked one. You can pass the clicked element directly to your function:
function planeChoice(element) {
// element refers to the clicked radio button
var plane = element.value;
switch (plane) {
//...
}
}
For that to work, you have to pass this to your function:
<input type="radio" name="planeButton" value="152"
onclick="planeChoice(this)" />
this refers to the HTML element you attach the event handler to, so in this case it refers to the <input> element.
To learn more about events, I suggest to read the articles on http://quirksmode.org, starting with Introduction to Events and Early event handlers.
Two suggestions for further improvement:
(A) You can use a map (which is just an plain object in JavaScript) instead of a switch statement to determine the corresponding message:
var map = {
"152": "A small two-place-airplane for flight training",
"172": "The smaller of two four-place airplanes"
// ...
};
A map is also easier to maintain (to extend).
Once you have the value of the radio button, you can access the message with:
alert(map[plane]);
You are not limited to store only primitive values (like strings), you can also store functions and call them if you want to do some more complex things. But to learn more about functions and how you can use them, you should read a JavaScript guide.
(B) You can use event delegation instead of binding the same event handler to every element (this works through event bubbling). The click event handler is attached to the <form> element:
<form onclick="planeChoice(event)" ...>
Or even better, get a reference to the form element and attach the event handler via JavaScript:
document.getElementById("myForm").onclick = planeChoice;
The passed event object holds information about which element was clicked:
function planeChoice (event) {
event = event || window.event; // for IE
var target = event.target || event.srcElement; // for IE
if(target.type === "radio") { // if a radio button is clicked
var plane = target.value;
// ... further code
}
}
Can I suggest you try using jQuery? It's a useful (and popular) JavaScript library that will help reduce and simplify the code you need.
For example, the above code could be simplified to this in jQuery:
$('#myForm input:radio').click(function(){
switch (this.value) {
case "152":
alert("A small two-place-airplane for flight training");
break;
// More Options go here...
default:
alert("Error in JavaScript function planeChoice");
break;
}
});
It would also eliminate the need to use click handlers on each radio button.
Related
The logic in the change() event handler is not being run when the value is set by val(), but it does run when user selects a value with their mouse. Why is this?
<select id="single">
<option>Single</option>
<option>Single2</option>
</select>
<script>
$(function() {
$(":input#single").change(function() {
/* Logic here does not execute when val() is used */
});
});
$("#single").val("Single2");
</script>
Because the change event requires an actual browser event initiated by the user instead of via javascript code.
Do this instead:
$("#single").val("Single2").trigger('change');
or
$("#single").val("Single2").change();
I believe you can manually trigger the change event with trigger():
$("#single").val("Single2").trigger('change');
Though why it doesn't fire automatically, I have no idea.
Adding this piece of code after the val() seems to work:
$(":input#single").trigger('change');
As far as I can read in API's. The event is only fired when the user clicks on an option.
http://api.jquery.com/change/
For select boxes, checkboxes, and
radio buttons, the event is fired
immediately when the user makes a
selection with the mouse, but for the
other element types the event is
deferred until the element loses
focus.
To make it easier, add a custom function and call it whenever you want to change the value and also trigger a change:
$.fn.valAndTrigger = function (element) {
return $(this).val(element).trigger('change');
}
and
$("#sample").valAndTrigger("NewValue");
Or you can override the val() function to always call the change when val() is called:
(function ($) {
var originalVal = $.fn.val;
$.fn.val = function (value) {
this.trigger("change");
return originalVal.call(this, value);
};
})(jQuery);
Sample at http://jsfiddle.net/r60bfkub/
In case you don't want to mix up with default change event you can provide your custom event
$('input.test').on('value_changed', function(e){
console.log('value changed to '+$(this).val());
});
to trigger the event on value set, you can do
$('input.test').val('I am a new value').trigger('value_changed');
If you've just added the select option to a form and you wish to trigger the change event, I've found a setTimeout is required otherwise jQuery doesn't pick up the newly added select box:
window.setTimeout(function() { jQuery('.languagedisplay').change();}, 1);
I ran into the same issue while using CMB2 with Wordpress and wanted to hook into the change event of a file upload metabox.
So in case you're not able to modify the code that invokes the change (in this case the CMB2 script), use the code below.
The trigger is being invoked AFTER the value is set, otherwise your change eventHandler will work, but the value will be the previous one, not the one being set.
Here's the code i use:
(function ($) {
var originalVal = $.fn.val;
$.fn.val = function (value) {
if (arguments.length >= 1) {
// setter invoked, do processing
return originalVal.call(this, value).trigger('change');
}
//getter invoked do processing
return originalVal.call(this);
};
})(jQuery);
$(":input#single").trigger('change');
This worked for my script. I have 3 combos & bind with chainSelect event, I need to pass 3 values by url & default select all drop down. I used this
$('#machineMake').val('<?php echo $_GET['headMake']; ?>').trigger('change');
And the first event worked.
To change the value
$("#single").val("Single2");
Also to trigger a change event
$("#single").val("Single2").change();
this logic is instrumental when multiple select options are on a page.
one changes and other select options have to change but do not trigger a change event.
There are 5 buttons where each button will do a different thing.
The first button will change a paragraph to green (in HTML file, Id="button1").
The second button will change a paragraph to blue (in HTML file, Id="button2").
window.onload = pageLoad;
function pageLoad() {
this.onclick = makeChange;
}
function makeChange() {
var paragraph = document.getElementById("paragraph");
if (this.id = "button1") {
paragraph.style.color = "green";
} else {
// change the color
}
}
This doesn't work because I can't get the id of the button, I tried to debug it using:
paragraph.innerHTML = this.id;// I got "undefined"
Is there anyway I can get which button is pressed, and based on which button is pressed, change the text color differently? I want to use only 1 function(exclude pageLoad) to do this and I don't to have 5 variableS and 5 onclick lines and no jquery.
var paragraph = document.GetElementById("button1");
var paragraph = document.GetElementById("button2");
var paragraph = document.GetElementById("button3");
....
You could try something like this. Keep the color you want to change the paragraph to inside the button, using a custom data-* attribute. Then access it with .getAttribute(). So your JS would be something like this:
function makeChange() {
var paragraph = document.getElementById("paragraph");
var newColor = this.getAttrbiute('data-color');
paragraph.style.color = newColor;
}
And your buttons would be like this:
<button data-color="green">Green</button>
<button data-color="blue">Blue</button>
This way you can easily change the target color by changing the data-color attribute.
As a side note, do make sure you're listening for the click event with your buttons, like this:
var buttons = document.querySelectorAll('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', makeChange);
}
Using an event listener to leverage Event Delegation has a few advantages over an on event (ex. onclick) property or attribute event handler:
Unlike on event handlers, event listeners can be used multiple times on multiple objects and elements.
By setting the 3rd parameter to true, you can listen for events in capture phase. It's rarely needed.
We can setup a pattern to take advantage of the 3 Event.eventPhases:
Capture: Starting from Event.currentTarget (ex. #set) the event chain goes down the DOM tree to the end of this phase is...
Target: The element that is the origin of the event is the Event.target (ex. #btn*).In simpler terms, e.target is the element clicked, checked, changed, etc. This element will be the context related to the event, in many ways e.target is like this (in this demo, e.target is one of the buttons and this is the ancestor (fieldset#set, e.cT)...
Bubbling: This is the phase after the callback is initiated and the event chain reverses its path back up to the Event.currentTarget. On its way up, should there be any other elements registered to this particular event would also be triggered. This may be an unwanted behavior depending on the developer's intentions and circumstances. For those cases, Event.stopPropagation() can be called (usually placed as the last statement in the callback). Upon reaching the end of the bubbling phase, the e.cT calls the callback (this callback will be in the context of e.target, this context allows us to identify the clicked button)
Event Delegation is a process in which we setup our event listener on a higher level in the DOM (an ancestor element), then at target phase the clicked button will be identified by referencing e.target. This gives us a powerful and eloquent way to handle an unlimited amount of elements with a single event listener. No on event handler is capable of doing this under normal circumstances without the use of specialized interface.
More details are commented in demo
Demo
/* Reference an ancestor element of all the buttons.
|| In this case the best choice would be
|| fieldset#set. You could also use <body>, document,
|| or even window, but the further the ancestor is,
|| the chances of unwanted behavior from other elements
|| become greater.
*/
var set = document.getElementById('set');
/* Register #set on the click event.
|| Now #set is considered the Event.currentTarget.
|| The e.cT (#set) will listen for the event (click)
|| to occur upon itself and any of its decsendants.
|| Once event occurs, #set (e.cT) will run the
|| callback function (findBtn).
*/
set.addEventListener('click', findBtn, false);
/* This is the callback function which is a normal
|| function that is called when a registered event
|| happens.
*/
function findBtn(e) {
// An array of 5 colors
var rainbow = ['purple', 'blue', 'green', 'yellow', 'red'];
// Reference to the paragraph (<p>)
var text = document.querySelector('p');
/* if e,target (the element clicked), is NOT
|| e.cT, then...
*/
if (e.target !== e.currentTarget) {
/*...and if e.T (Event.target) tagName is
|| 'BUTTON', then...
*/
if (e.target.tagName === 'BUTTON') {
// ...get the button's #id
var tgtID = e.target.id;
/* The id of each button is basically just
|| an index number. Although I do not
|| recommend it normally, it is valid to start
|| with a number for an #id.
|| This statement uses the style property to
|| access the paragraph's CSS color property
|| and changes the value according to the
|| index of the rainbow array which in turn is
|| determined by the e.T (button clicked) #id
*/
text.style.color = rainbow[tgtID];
}
}
// End function
return false;
}
<fieldset id='set'>
<legend>Event Delegation</legend>
<button id='0'>Purple</button>
<button id='1'>Blue</button>
<button id='2'>Green</button>
<button id='3'>Yellow</button>
<button id='4'>Red</button>
</fieldset>
<p>Click any of the five buttons to change this text.</p>
The Code
I set up a jsFiddle at http://jsfiddle.net/6vd5C/1/
The JavaScript code in question:
var global_loggedOnUser = "User1";
$(function(){
var viewmodel = (function(){
this.feedbacktype = ko.observable("None");
this.currentPage = ko.observable(location.href);
this.currentUsername = global_loggedOnUser;
this.updateFeedbackType = function(item, event)
{
var newText = $(event.target).children("span").text();
feedbacktype(newText);
};
return{
pageUserIsOn : currentPage,
theUser : currentUsername,
feedbackType: feedbacktype
};
})();
ko.applyBindings(viewmodel);
});
The Goal
Whenever someone clicks on the button of the submission, I'd like to see the "Current Type" bullet point update to indicate caption on the clicked button.
The Problem
Sometimes the text updates to the correct words; sometimes it updates but is a null value.
I cannot find a pattern or rhyme/reason; sometimes after being blank, clicking another element and then clicking the element that previously returned null now returned the correct text.
What am I doing wrong?
Instead of using $(event.target) use $(event.currentTarget).
I'd like to expand a bit and explain the difference, when you use event.target you're getting the element that dispatched the event (the actual element literally) - like in your case, if you click on the <i></i> element which is nested within the button element, it will return the <i></i> notice that if you return the code to event.target and you click on the edge of your button it will work as expected.
In the case of event.currentTarget you're getting the element you're binding your listener to (which in your case is the actual button).
In jqGrid, Is there a "built-in" way to know what mouse button was clicked, before row selection?
Currently we have jqGrid with some actions bind on "onSelectRow" event of jqGrid. The problem is that when user right click on that row, onSelectRow event raised to and action performed. What I need, is to ignore "onSelectRow" when user right click on a row.
EDIT: I know there exists onRightClickRow event, but it raised after onSelectRow and action already performed.
I found that I can know what button clicked by "type" of event object. When it's click, the type is "click" when it's right click, the type is "contextmenu"....Does exists the additional way, or I must check type to know what button is clicked?
Thanks
It's good question! The reason of such behavior is the following. jqGrid register an event handler for the event contextmenu on the whole grid <table> element with the following code (see here)
.bind('contextmenu', function(e) {
td = e.target;
ptr = $(td,ts.rows).closest("tr.jqgrow");
if($(ptr).length === 0 ){return;}
if(!ts.p.multiselect) { $(ts).jqGrid("setSelection",ptr[0].id,true,e); }
ri = ptr[0].rowIndex;
ci = $.jgrid.getCellIndex(td);
$(ts).triggerHandler("jqGridRightClickRow", [$(ptr).attr("id"),ri,ci,e]);
if ($.isFunction(this.p.onRightClickRow)) {
ts.p.onRightClickRow.call(ts,$(ptr).attr("id"),ri,ci, e);
}
});
How one can see from the code it calls setSelection method and calls onRightClickRow callback and trigger jqGridRightClickRow event. So if you don't need the selection of rows and if you don't use onRightClickRow and jqGridRightClickRow you can just unbind the event handler:
$("#list").unbind("contextmenu");
If you do want use onRightClickRow callback or if you don't sure whether you need to use jqGridRightClickRow somewhere you can "subclass" the event handler. The implementation is depend a little from the version of jQuery which you use. Starting with jQuery 1.8 one should use a little another call to get the current events registered on the DOM element. The corresponding code could be about the following:
//$grid.unbind('contextmenu');
var getEvents = $._data($grid[0], "events"); // $grid.data("events") in jQuery ver<1.8
if (getEvents && getEvents.contextmenu && getEvents.contextmenu.length === 1) {
var orgContextmenu = getEvents.contextmenu[0].handler;
$grid.unbind('contextmenu', orgContextmenu);
$grid.bind('contextmenu', function(e) {
var oldmultiselect = this.p.multiselect, result;
this.p.multiselect = true; // set multiselect to prevent selection
result = orgContextmenu.call(this, e);
this.p.multiselect = oldmultiselect; // restore multiselect
return result;
});
}
The demo demonstrate the above code live.
Events are listed here: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events
There is an onRightClickRow event.
Also, using the plain jquery event object and which will tell you. http://api.jquery.com/event.which/
You must use 3rd parameter to onRowSelected and which or the type like you mentioned.
I have a pretty simple form. When the user types in an input field, I want to update what they've typed somewhere else on the page. This all works fine. I've bound the update to the keyup, change and click events.
The only problem is if you select an input from the browser's autocomplete box, it does not update. Is there any event that triggers when you select from autocomplete (it's apparently neither change nor click). Note that if you select from the autocomplete box and the blur the input field, the update will be triggered. I would like for it to be triggered as soon as the autocomplete .
See: http://jsfiddle.net/pYKKp/ (hopefully you have filled out a lot of forms in the past with an input named "email").
HTML:
<input name="email" />
<div id="whatever"><whatever></div>
CSS:
div {
float: right;
}
Script:
$("input").on('keyup change click', function () {
var v = $(this).val();
if (v) {
$("#whatever").text(v);
}
else {
$("#whatever").text('<whatever>');
}
});
I recommending using monitorEvents. It's a function provide by the javascript console in both web inspector and firebug that prints out all events that are generated by an element. Here's an example of how you'd use it:
monitorEvents($("input")[0]);
In your case, both Firefox and Opera generate an input event when the user selects an item from the autocomplete drop down. In IE7-8 a change event is produced after the user changes focus. The latest Chrome does generate a similar event.
A detailed browser compatibility chart can be found here:
https://developer.mozilla.org/en-US/docs/Web/Events/input
Here is an awesome solution.
$('html').bind('input', function() {
alert('test');
});
I tested with Chrome and Firefox and it will also work for other browsers.
I have tried a lot of events with many elements but only this is triggered when you select from autocomplete.
Hope it will save some one's time.
Add "blur". works in all browsers!
$("input").on('blur keyup change click', function () {
As Xavi explained, there's no a solution 100% cross-browser for that, so I created a trick on my own for that (5 steps to go on):
1. I need a couple of new arrays:
window.timeouts = new Array();
window.memo_values = new Array();
2. on focus on the input text I want to trigger (in your case "email", in my example "name") I set an Interval, for example using jQuery (not needed thought):
jQuery('#name').focus(function ()
{
var id = jQuery(this).attr('id');
window.timeouts[id] = setInterval('onChangeValue.call(document.getElementById("'+ id +'"), doSomething)', 500);
});
3. on blur I remove the interval: (always using jQuery not needed thought), and I verify if the value changed
jQuery('#name').blur(function ()
{
var id = jQuery(this).attr('id');
onChangeValue.call(document.getElementById(id), doSomething);
clearInterval(window.timeouts[id]);
delete window.timeouts[id];
});
4. Now, the main function which check changes is the following
function onChangeValue(callback)
{
if (window.memo_values[this.id] != this.value)
{
window.memo_values[this.id] = this.value;
if (callback instanceof Function)
{
callback.call(this);
}
else
{
eval( callback );
}
}
}
Important note: you can use "this" inside the above function, referring to your triggered input HTML element. An id must be specified in order to that function to work, and you can pass a function, or a function name or a string of command as a callback.
5. Finally you can do something when the input value is changed, even when a value is selected from a autocomplete dropdown list
function doSomething()
{
alert('got you! '+this.value);
}
Important note: again you use "this" inside the above function referring to the your triggered input HTML element.
WORKING FIDDLE!!!
I know it sounds complicated, but it isn't.
I prepared a working fiddle for you, the input to change is named "name" so if you ever entered your name in an online form you might have an autocomplete dropdown list of your browser to test.
Detecting autocomplete on form input with jQuery OR JAVASCRIPT
Using: Event input. To select (input or textarea) value suggestions
FOR EXAMPLE FOR JQUERY:
$(input).on('input', function() {
alert("Number selected ");
});
FOR EXAMPLE FOR JAVASCRIPT:
<input type="text" onInput="affiche(document.getElementById('something').text)" name="Somthing" />
This start ajax query ...
The only sure way is to use an interval.
Luca's answer is too complicated for me, so I created my own short version which hopefully will help someone (maybe even me from the future):
$input.on( 'focus', function(){
var intervalDuration = 1000, // ms
interval = setInterval( function(){
// do your tests here
// ..................
// when element loses focus, we stop checking:
if( ! $input.is( ':focus' ) ) clearInterval( interval );
}, intervalDuration );
} );
Tested on Chrome, Mozilla and even IE.
I've realised via monitorEvents that at least in Chrome the keyup event is fired before the autocomplete input event. On a normal keyboard input the sequence is keydown input keyup, so after the input.
What i did is then:
let myFun = ()=>{ ..do Something };
input.addEventListener('change', myFun );
//fallback in case change is not fired on autocomplete
let _k = null;
input.addEventListener( 'keydown', (e)=>_k=e.type );
input.addEventListener( 'keyup', (e)=>_k=e.type );
input.addEventListener( 'input', (e)=>{ if(_k === 'keyup') myFun();})
Needs to be checked with other browser, but that might be a way without intervals.
I don't think you need an event for this: this happens only once, and there is no good browser-wide support for this, as shown by #xavi 's answer.
Just add a function after loading the body that checks the fields once for any changes in the default value, or if it's just a matter of copying a certain value to another place, just copy it to make sure it is initialized properly.