I never used name attribute, but in MVC looks like i must.
I have
<select name="testname" onChange="Alert()">
<option value="8">Test</option>
</select>
JS
function Alert(){
alert(this.name);
}
Result should be alert("testname")
Its simple, but i never used, and its hard to find on google, since everyone asking about getting value or index :D
The problem is that due to the way you call Alert, this refers to window, not to the DOM element. You could pass it to the function as argument:
<select name="testname" onchange="Alert(this)">
and
function Alert(element){
alert(element.name);
}
There are better ways to attach event handlers than using HTML attributes. I recommend to read the various articles about event handling on quirksmode.org.
Also make sure you understand how this works.
Of course you could also write
<select name="testname" onchange="alert(this.name)">
If you are using jQuery, then you should use it to bind the event handler. For example:
$('select[name=testname]').change(function() {
alert(this.name);
});
Have a look at a jQuery tutorial and take the time to go through the API documentation, it's worth it.
Related
Although it has already been asked, I want to adress the issue of correct jQuery programming.
Method #1:
<script>
function DoClickAction() {
// Some work
return false;
}
</script>
Do some work
VS
Method #2:
<script>
$(function() {
$("#ActionButton").on("click", DoClickAction);
}
function DoClickAction() {
// Some work
return false;
}
</script>
Do some work
I'm having a discussion with my colleagues about this, and my opinion is that both methods have enough pro and cons to not be able to say "this is the right way", but if I have to choose I tend to prefer Method #1, this is why:
Method #1 pros:
When debugging someone else code, you can easily follow which jQuery code is executed when somebody presses the link.
When you dynamically load (AJAX call) the content, it will always work, no need to rebind your jQuery events.
Method #2 pros:
It will produce less HTML code for the browser to download, because the script file will be cached and the onclick attribute is not necessary. Although this example uses more code.
You can re-use the code easily by using the same attributes, although using the onclick with 1 function is kind of the same thing.
What are your thoughts on this?
Instead of listing the pro's of either method, let me focus on the con's of method 1:
Change a function name == change the entire markup
All event handlers reside in the global scope. Working with closures can be a bit of a pain, then.
adding new elements dynamically (through JS or via ajax response) means that you'll either have to parse the markup and add the attribute one by one, or you'll have to send markup containing, essentially, JS function calls. Not safe, not clean
Each attribute is a new listener. The more attributes you have, the heavier the event loop will become
Mixing JS and HTML is not considered good practice. Think of it as separation of concern. The markup is there to provide the client with a UI. JS's job (in a browser) is to enhance the user experience. They have to work together, but have different tasks. Hence, they should be treated as separate entities.
As far as the second method goes, the only "cons" I can think of are:
Your code is slightly harder to understand, but if somebody can't work out what an event listener is, he shouldn't be working on your code, IMO.
Debugging can be harder, and older browsers might leak (jQ does contain an awful lot of X-browser related code, so it doesn't apply here. It does when you're writing vanillaJS)
In addition to this, method2 has another major pro, that you've not listed: delegation. At first, delegation looks hard, but It's easy, jQuery's $.delegate makes it easier, still, using $.on with a selector also delegates the event.
Basically, delegation allows you to deal with all events, for example click, for the entire page, or a section of the page, using a single listener. This as opposed to binding the event to each and every element. Thus: 1 listener on the event loop versus tens/hundreds. It's pretty obvious which is the more performant way of doing things.
Suppose you have a navigation div on a page, that looks like this:
<div id='nav'>
<ul>
<li id='nav-home'>Some pseudo-link</li>
<li id='nav-page1'>Another</li>
</ul>
</div>
You want to pick up on the user, clicking one of the <li> tags. The first method you listed makes for a right mess: <li id='nav-home' onclick='clickNav(event, this)'>. I'm passing the event object and this (a DOM reference) to have access to everything delegation gives me access to.
Using delegation, I can simply do this:
//jQ
$('#nav').on('click','li',function(e)
{
$.ajax({//you know the gist
url: 'ajax/' + $(this).id().replace('nav-',''),
success: function(){}
});
});
//vanillaJS:
document.getElementById('nav').addEventListener('click',function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
if (e.tagName.toLowerCase() === 'li')
{
//perform ajax call
}
},false);
I myself am very much partial to #2, as it provides a clean separation of JavaScript and HTML. The negatives of not having the action of a button be immediately visible in the HTML can be completely negated by browser plugins.
Furthermore, as you've already stated, sometimes I want to attach an onclick event to, say, every row of a table, and setting the OnClick attribute of an element on every row is much more wasteful than simply attaching a click handler to each of them with a single line of code elsewhere.
I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.
I'm using angularJS. I have a few <select> elements on my page, each with its own ng-change, for example:
<select id="hairColorComponent" ng-model="hairColor"
ng-options="option.name for option in hairColorData"
ng-change="updateUserData()">
I want to be able to determine which DOM element got updated from within the updateUserData function, without having to manually specify it as a parameter for each ng-change attribute.
Is there an event, or caller or something similar that I can use within the context of updateUserData?
Hopefully something like ng-change="updateUserData(caller)"
There's no (easy) way to do this by design. Angular controllers are supposed to be completely separate of the DOM, so if you find yourself needing to reference the DOM in them you're probably approaching things the wrong way.
If your HTML is
<select id="hairColorComponent" ng-model="hairColor"
ng-options="option.name for option in hairColorData"
ng-change="updateUserData()">
Then changing the select will change the value of $scope.hairColor in your controller. In updateUserData() just read its value and act accordingly.
If in your situation there's really no way to do it except referencing the DOM, you could do it by writing a custom directive. In general, direct DOM manipulation in Angular should be a last resort kind of measure though.
Found this on google, I eventually solved my problem so here's my solution.
If you just need the ID, you could always just pass that as a parameter.
<select id="hairColorComponent" ng-model="hairColor"
ng-options="option.name for option in hairColorData"
ng-change="updateUserData('hairColorComponent')">
Still not super clean, but it solved my problem. Since I actually needed the dom element, I then used jQuery to get the element.
$scope.updateUserData = function (id) {
var element = jQuery('#'+id);
};
(For those wondering, I'm doing my best with converting legacy code that "magically" saves user settings on pages all over the website.)
Wondered if there was good way to do this, thought I would post to the SO community...
There is a 3rd party web page that I have no control over how it renders, but they allow me to add JQuery.
Using the JQuery, I am creating a nav menu on the side of the page, it will be a list of links. The onclick event of these links I get from existing onclick events already on the page, but when I do a:
var linkLoc = $('#theLink').attr("onclick");
linkLoc returns:
function onclick(event) {
handleJumpTo("com.webridge.entity.Entity[OID[E471CB74A9857542804C7AC56B1F41FB]]", "smartform");
}
instead of what I would expect:
handleJumpTo("com.webridge.entity.Entity[OID[E471CB74A9857542804C7AC56B1F41FB]]", smartform");
I think JQuery is trying to get the event for binding, but I need the actual Javascript markup since I'm creating the HTML dynamically. I guess I could substring the "function onclick(event) {" out, but seems kind of hacky.
Any ideas of an elegant way I could get the onclick markup?
$("#theLink") would return a jQuery object whereas $("#theLink")[0] would give a DOM object. This is a resson that $("#thelink")[0].getAttributeNode('onclick').value would work.
The type of $('#theLink').attr("onclick") is a function, so you can just use that when you bind events to the links.
var linkLoc = $('#theLink').attr("onclick");
$('a#link1').live('click', linkLoc);
Example: http://jsfiddle.net/BdU6f/
You can also run other code in the click handler too, if you need:
var linkLoc = $('#theLink').attr("onclick");
$('a#link1').live('click', function(e){
// Code...
linkLoc(e);
});
Example: http://jsfiddle.net/BdU6f/1/
The "onfoo" attributes have values that are functions, not strings. The semantics of:
<whatever onclick='code code code'>
are that the browser constructs a function object as if you had code that did this:
document.getElementById('whatever').onclick = new Function("event", "code code code");
Thus you don't really need the raw string, since you've got something better: the function itself, ready to be called. You can then bind it as a handler to other elements via JavaScript code, not HTML (which is really a better way to do things anyway). You're using jQuery, you say, so you can use the jQuery ".bind()" API to bind those functions to whatever elements you need.
You should also be aware that there are other ways of binding event handlers to elements, ways that will leave the "onfoo" attributes completely unset.
If I understand where you're going with this, you should be able to assign the returned onclick function straight through to the onclick of your new nav element...
$('#NewNavElement').click($('#theLink').attr('onclick'));
If you need to add additional code to the handler, you can just bind another click handler.
try this;
$('#theLink').getAttributeNode('onclick').value
Revised as per comment:
$('#theLink').get().getAttributeNode('onclick').value
I seem unable to correctly attach the onchange event to a dijit.form.Select widget. However, I am new to web development, so I could be doing something completely idiotic (although, as best I can tell (and I've read all the docs I could find) I'm not). I made sure the body class matches the dojo theme, that I dojo.require() for all the widgets I use (and dojo.parser), and still, nada. The code I'm using is:
dojo.addOnLoad(function () {
var _query = dojo.query('.toggle');
for (var i in _query) {
dojo.connect(_query[i], 'onchange', function (ev) {
console.log(ev + ' fired onchange');
});
}
});
Any help at all would be appreciated.
Addition: after digging more into the internals of how dijit renders widgets, I discoverd that when I add the dojoType='dijit.form.Select' attribute-value pair to my html element (doing this declaratively), dijit actually renders a one-row two-col table. The table's first element is a span (with the class dijitSelectLabel) that I'm assuming just displays the selected (or default) element. It's second element appears to be a button rendered as a down arrow that toggles the display of the menu itmes in response to certain DOM events. Also (and I thought this was pretty nifty), dijit doesn't actually place the select options in the DOM tree until one of those events is triggered. I looked at the HTML in firebug right after a fresh pageload (before i clicked on anything), and the second option isn't anywhere to be found. Then, once I click on the arrow button, there's a dijit.Menu widget, dijit sticks a dijit.Menu to the end of the body node; after I click somewhere else, the Menu widget is still the body's lastChild, now its just hidden and not attached to the form.Select widget.
Should it really be this complicated if all I want to do is place a different dijit.form widget in the DOM tree depending on what item the user selects?
Conclusion:
Turns out it was a capitalization issue.
dojo.connect(widget_obj, 'onChange', function_obj);
works, whereas
dojo.connect(widget_obj, 'onchange', function_obj);
doesn't.
So I was right that I was being completely stupid. I assumed that because the all lowercase version works when putting placing in it an html tag as an attribute, that Dojo would treat it the same. It makes sense, because dijit.form.Select has no .onchange attribute, but does have a .onChange attribute. (I ended up sticking with a .Select over a .FilteringSelect because I don't my users to be given any impression that they can type in something.) So, which one of you guys do I give the answer to (because you both had onChange in your posts, I guess I was just too inexperienced to realize that the case mattered)?
For anyone else finding this page through a web search, you may have made the same mistake I did .. copy-pasting your markup such that each has the same 'value'.
e.g.
<select dojoType='dijit.form.Select' onChange="fn">
<option value='foo'>Foo 1</option>
<option value='foo'>Foo 2</option>
<option value='foo'>Foo 3</option>
</select>
fn() will never be called, because the change handler code checks the new value against the previously selected value and does not fire onChange unless it's changed.
Try the following when doing a dojo.connect:
var inputEvents = []; //Global var
inputEvents.push(dojo.connect(dijit.byId(inputFldStr), "onChange", eventFuncObj));
Store the connection in a global var.
In your code you connect a handler to 'onchange' event of dom nodes, not dojo widgets. dojo.query returns you a NodeList object - a collection of nodes that match the query.
In this case it's more reliable to connect to a widget's 'onChange' event, as GoinOff showed. Just a little addition to his answer to make sure you're doing this right.Assume this is your html (in later versions of Dojo dijit.form.Select has been replaced with dijit.form.FilteringSelect):
<input dojoType="dijit.form.FilteringSelect" id="stateInput" store="stateStore" searchAttr="name" name="state"/>
Then you would connect to 'onChange' this way (you also can store the connection in some array to be able to disconnect it later, as GoinOff suggested):
dojo.addOnLoad (function () {
dojo.connect(dijit.byId("stateInput"), "onChange", function(){});
}
But it's another story if you don't know your widget's id and want to use dojo.query to connect to multiple widgets.