My normal way of performing javascript transforms on lots of elements in via JQuery:
<div class="cow"></div>
<script> $(".cow").doStuff() </script>
However, this operation is fragile and brittle: it works on the assumption that the page is all loaded only once. Once you start getting into Ajax and partial reloads, this sort of global transform breaks down completely. It also doesn't work if the server wants to do a different transform to each element based on some serverside data.
I know the actual onload event for non-body elements doesn't work. One solution is to give all the elements IDs/classes and reference them immediately using JQuery:
<div id="cow"></div>
<script> $("#cow").doStuff() </script>
However, that is really messy; I do not like it at all, partly because every element I give an ID pollutes the global I namespace. I am currently giving the element an effectively non-collidable ID
<div id="id877gN0icYtxi"></div>
<script> $("#id877gN0icYtxi").doStuff() </script>
based on random base64 numbers. However, this all seems like a giant hack: I can give the elements onclicks and onmousedowns and such very simply using their respective attributes, which then call a function to transform the given this.
Now, I know onload doesn't work. However, is there any way to simulate its functionality? Specifically, I want to be able to run javascript code referencing a particular tag using this without having to assign the tag an ID to them.
EDIT: Essentially I want something like
<input onclick="alert('moo')"/>
but for oncreate; my current use case is to fill an input or textarea with text, and I am currently doing:
<input id="id877gN0icYtxi"/>
<script>$("#id877gN0icYtxi").val(...)</script>
where the ... is different for every input box, and thus cannot be done easily using a "global" jquery transform. On the other hand, I cannot just set the value or attribute of the input when i create it, as it may be a textarea, and i wouldn't know. I want to do something like:
<input onload="$(this).val(...)"/>
Which doesn't work, but I wish it did. Again, the ... is set by the server and different for every input tag on the page.
EDIT2:
I'm well aware of hour JQuery is typically used to do whole-document transforms on lots of elements in the same way. The issue is that in this case, each element is being transformed in a way specific to that element, dictated by the server. The specific use case is each field has its contents pre-filled in by $().val(), and naturally every field will be filled with different contents. Giving each element a unique ID and using JQuery to do a global search to find that element again seems like an incredibly roundabout way of doing things, and of course breaks when you start Ajaxing parts of your page in and out.
EDIT3:
In short, i want to be able to write
<div onload="javascriptFunction(this)"/>
and have javascriptFunction() be run on when the <div> is created (whether it is on the initial page or inserted via ajax) and be passed the <div> as a parameter. Just as onclick would run javascriptFunction() with <div> as a parameter when the div is clicked, I want the same thing to happen, but when the <div> is created/inserted into the DOM.
I'm willing to accept any amount of setup scripts in the <head> in order to make this happen. For reasons mentioned above, I am not willing to add any <script> tags after the <div>, or to add a class or id to the <div>. Given these limitations, what's the best that can be done to simulate an onload attribute for non-body elements?
There's no such onload event in DOM spec, however DOM Level 2 spec provides Mutation event types, to allow notification of any changes to the structure of a document, including attr and text modifications, currently only modern browsers support such events and it is buggy in Internet Explorer 9!
However you could use DOMNodeInserted event to monitor the document for any change:
$(document).live("DOMNodeInserted", function(e){
$(e.target).val(...);
});
You should be careful using Mutation events, at least try to be updated! According to W3C:
Mutation event types has not yet been completely and interoperably
implemented across user agents, A new specification is under development with the aim of addressing the use cases that mutation events solves, but in more performant manner.
I guess if you google the matter, you might find some cross browser/jquery plugin for this, just in case, these links migh help:
https://developer.mozilla.org/en/DOM/Mutation_events
http://help.dottoro.com/ljfvvdnm.php#additionalEvents
http://help.dottoro.com/ljmcxjla.php
http://help.dottoro.com/ljimhdto.php
http://www.bennadel.com/blog/1623-Ask-Ben-Detecting-When-DOM-Elements-Have-Been-Removed-With-jQuery.htm
All this depends on what sort of tags you want to work with.
One thing to know is that jQuery lets you select a lot of items at once, so when you do something like $('p'), that object refers to all the p nodes.
Doing something like $('p').hide() hides all the p nodes.
jQuery selectors are (at least) as powerful as CSS selectors, so you can do some pretty semantic things in single lines.
Imagine if you had something like a list of reply boxes for a comments section or something:
-----------------------------------------
Comment #1
blah blah blah blah blah
[ Text field ] (Reply)
-----------------------------------------
Comment #2
nyark nyark nyark nyark
[ Text field ] (Reply)
-----------------------------------------
Comment #3
ubadabuba
[ Text field ] (Reply)
-----------------------------------------
Comment #4
eeeeeeeeeeeeeeeeeeeeeeeeee?
[ Text field ] (Reply)
So your DOM layout might look something like
<div class="comment" >
<h1> Comment #1 </h1>
<p> blah blah blah blah blah </p>
<input /> <button >Reply </button>
</div>
<div class="comment" >
<h1> Comment #2 </h1>
<p> nyark nyark nyark nyark </p>
<input /> <button >Reply </button>
</div>
so if you want to update all your input fields, to put in a default text, you just need to see that the CSS selector for your fields is .comment > input.
After that the JS appears by itself
$(document).ready(function(){
var inputs=$('.comment > input ');//references all the input fields defined by this selector
inputs.attr('value','default text');//set the value of the text in the input
})
Example shown here
Giving elements an ID doesn't "pollute the global namespace", it's just a mechanism for referencing elements. You only need an ID for an element that you intend referencing by ID. Giving IDs to other elements isn't harmful, just unnecessary.
You can reference elements by a number of criteria, including class and their position in the DOM (any method in the CSS selectors pool and also DOM relationships—parent, child, sibling, etc.). The method you chose may have advantages and disadvantages depending on how you are using it, there is no inherently "good" or "best" way to do it, just that some methods will suit some cases better than others.
If you want to replace, say, listeners after replacing elements in the DOM, then your for replacing the elements needs to account for that. Event delegation is one strategy, there are others.
What about window.onload() ?
Related
I want to mark a section of text to dynamically edit with JavaScript.
After skimming through the List of Inline Elements, I decided to use <a> tag, which seems like a no-brainer choice.
function updatePrice() {
var current = Number($(".price").text());
$(".price").text(1 + current);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>This item is $<a class="price">1</a></p>
<button onClick = "updatePrice();">One Up!</button>
I played around with <var> tag as well, but it seems to be a wrong usage for the tag - it's supposed to be used for the name of the variable
, not the variable itself.
While <a> seems to be the best choice, it seems like a wrong usage for the tag:
The HTML <a> element (or anchor element) creates a hyperlink to other
web pages, files, locations within the same page, email addresses, or
any other URL.
Am I missing something?
Is this something that we accept like usage of <i> as an icon tag?
Am I being too picky about the definition and intended usage of the
tags?
Is this something HTML doesn't care about since it's origin doesn't care about such usage?
I'm asking the question to understand the topic at a scholastic level.
If there is no element with appropriate semantics (and <a> doesn't for this) then <div> and <span> are the generic fallback elements. <span> is inline, so use that.
<span> is what you need.
Two types of tags in HTML
Semantic clearly defines its contents and has specific rules and roles. <ul> -> <li> or p or a
Non-Semantic Totally tells nothing about its content and they don't have any rules or roles. Example: <span> or <div>
HTML is for machines, not for humans to understand. So we should split tags into two parts. One for machines to understand and give specific roles (semantic) and one for us to provide not important contents (non-semantic).
When browser parses an <a> tag, it creates a special role for it. It is designed for navigation. And also search engines, screen readers try to use them for navigation. When search engine parses <h1>, it understands that this may be the title of the page and give more importance to it.
But non-semantic tags are totally unimportant for the machines. They don't have a specific role except for holding some content.
So we should be using non semantic tags to mark special contents for us. Maybe we will use selectors or styles, it is up to us.
Why you shouldn't use div?
<div> is a block element which wants to contain line.
<span> is an inline element.
<span> is totally non-semantic and has no meaning except for creating special contents with different styles or using with special types of functions like your case.
But the important thing here is understanding what semantic and non-semantic tags are.
As Ahmet Can Güven suggested and Andrew Lohr agreed with in the comments to the question, <span> tag seems to be the best tag to achieve the goal, as:
<span> is very much like a element, but is a block-level
element whereas a <span> is an inline element.
and is:
generic inline container for phrasing content, which does not
inherently represent anything.
function updatePrice() {
var current = Number($(".price").text());
$(".price").text(1 + current);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>This item is $<span class="price">1</span></p>
<button onClick = "updatePrice();">One Up!</button>
I have a
<div id="content">
</div>
and three js variables that store different html: content1, content2 and content3.
By user interactions, the content of mentioned above div changes to one of that that stored in js variables.
What is preferable either to directly set div content to what I need by user interaction:
$("#content").html(content2);
or to change div structure to:
<div id="content">
<div id="c1">
// value of content1 variable here
</div>
<div id="c2">
// value of content2 variable here
</div>
<div id="c3">
// value of content3 variable here
</div>
</div>
And doing hide() and show() to that inner blocks, i.e when I want content2 to be shown:
$("#c1").hide();
$("#c2").show();
$("#c3").hide();
?
I'd say hiding & showing divs.
It's less intensive, and if the content inside the javascript variables happens to contain elements that you'll bind to, you won't have to rebind everytime you refresh the content, and if you wanted to have some sort of animation between the different content, multiple divs also allows that.
As a side note, using jQuery it's less code to do something like
$("#c2").show().siblings().hide();
The two aren't really all-that comparable since they do different things. They may well give a similar perception but what's happening isn't the same in terms of markup. In fact, it's not uncommon to see .html('Something').show() chained together.
Passing a string to .html() replaces the content of the selected element, it does nothing to affect the element itself.
Calling .show() or .hide() only affects the element itself - all the descendants remain exactly the same, they just can't be seen because their parent is not being displayed.
By using .html() you are replacing everything inside your element. All references to these descending elements will become undefined and direct (non-delegated) event listeners will also be lost.
.hide() and .show() do exactly what they say. The data inside your element is still preserved, the event handlers still in place, it's all just 'hidden' by way of display: none.
If the content dynamically changes, without page-load, use .html(), if not, .show() and .hide() are more appropriate.
For the ease of use and shorter more cleaner looking code, setting the content through HTML is the right option!
Think of it as what you're trying to do, 1 DIV => Can contain 3 different contents, you can manipulate it through JS.
So, in your first solution, you actually have one div and manipulating it through JS:
$("#content").html(content1);
$("#content").html(content2);
$("#content").html(content3);
Whereas, in the second solution, you are actually using 4 divs for the same functionality! So definitely, if you can do something with 1 div. That's the preferred way.
They both are taking equal lines for JS, but with the second approach, your HTML will contain a lot more code considering your contents are large.
I think that the best solution is to store the different contents into three variables and then assign to the div the choosen one with
$("#content").html(content2);
In this way you have three less nodes on your DOM tree
There isn't that much difference between the two options. One factor that might affect this is the actual size of the content you are changing. If the content is relatively small then it really doesn't matter which way you choose.
Another thing to consider is how available the three versions of the content variable is. If you have to fetch this HTML content each time you load it then it might make sense to pre-populate the content before you display it to your users so as to save the time it takes to load it. Then just show/hide the appropriate content.
I want to write a select something like...
#window_4 > content > p:eq(0)
I think I have this correct, but I have a few selectors that are all similar but I can't test them all at once.
Am I right in saying this is selecting an element, who is the fist p tag child of a content tag that is a child of a tag with id 'window_4'
If I have gotten this wrong, can you give me some pointers. Would love to be able to simplify this code, I have more code selecting the tag I am after then actually doing stuff with them.
Looks good to me, although you can make it a bit more readable by substituting p:eq(0) for p:first.
Edit for comment:
jQuery always returns an array of elements, no matter whether 0, 1 or many elements were found. On these elements, yes, you can perform JS functions, such as innerHTML. You can access each element returned by jQuery just as if you would any other array:
$(".red")[0].innerHTML = "Glen Crawford";
More info: http://groups.google.com/group/jquery-ui/browse_thread/thread/34551a757f139ae1/20111f82c2596426
Given the following markup.
<div id="example">
<div>
<div>
<input type='hidden'></input>
</div>
</div>
</div>
How can I quickly get the hidden input element given I have the ID for the top most div element with the ID 'example'?
I can hack away at it so I can just iterate through each child element until I hit the input, however, I'd like to improve on that and utilize Prototype and simply jump to that hidden input given the div.
Thanks!
Prototype provides a whole bunch of ways to do this:
// This, from Bill's answer, is probably the fastest, since it uses the
// Browser's optimized selector engine to get straight to the element
$$('#example input[type=hidden]').first();
// This isn't bad either. You still use the browser's selector engine
// To get straight to the #example element, then you must traverse a
// (small) DOM tree.
//
// element.down(selector) selects the first node matching the selector which
// is an decendent of element
$('example').down('input');
// Here, you'll get an array containing all the inputs under 'example'. In your HTML
// there is only one.
$('example').select('input')
// You can also use element.select() to combine separate groups of elements,
// For instance, if you needed all the form elements:
$('example').select('input', 'textarea', 'select');
$$('#example input[type=hidden]').first()
I prefer the direct approach
document.forms[0].fieldName.value
Which is less code, no need to use jQuery and is more friendly to code design.
I write a lot of dynamically generated content (developing under PHP) and I use jQuery to add extra flexibility and functionality to my projects.
Thing is that it's rather hard to add JavaScript in an unobtrusive manner. Here's an example:
You have to generate a random number of div elements each with different functionality triggered onClick. I can use the onclick attribute on my div elements to call a JS function with a parameter but that is just a bad solution. Also I could generate some jQuery code along with each div in my PHP for loop, but then again this won't be entirely unobtrusive.
So what's the solution in situations like this?
You need to add something to the divs that defines what type of behaviour they have, then use jQuery to select those divs and add the behaviour. One option is to use the class attribute, although arguably this should be used for presentation rather than behaviour. An alternative would be the rel attribute, but I usually find that you also want to specify different CSS for each behaviour, so class is probably ok in this instance.
So for instance, lets assume you want odd and even behaviour:
<div class="odd">...</div>
<div class="even">...</div>
<div class="odd">...</div>
<div class="even">...</div>
Then in jQuery:
$(document).load(function() {
$('.odd').click(function(el) {
// do stuff
});
$('.even').click(function(el) {
// dostuff
});
});
jQuery has a very powerful selector engine that can find based on any CSS based selector, and also support some XPath and its own selectors. Get to know them! http://docs.jquery.com/Selectors
I would recommend that you use this thing called "Event delegation". This is how it works.
So, if you want to update an area, say a div, and you want to handle events unobtrusively, you attach an event handler to the div itself. Use any framework you prefer to do this. The event attachment can happen at any time, regardless of if you've updated the div or not.
The event handler attached to this div will receive the event object as one of it's arguments. Using this event object, you can then figure which element triggered the event. You could update the div any number of times: events generated by the children of the div will bubble up to the div where you can catch and handle them.
This also turns out to be a huge performance optimization if you are thinking about attaching multiple handlers to many elements inside the div.
I would recommend disregarding the W3C standards and writing out HTML-properties on the elements that need handlers attached to them:
Note: this will not break the rendering of the page!
<ul>
<li handler="doAlertOne"></li>
<li handler="doAlertTwo"></li>
<li handler="doAlertThree"></li>
</ul>
Declare a few functions:
function doAlertOne() { }
function doAlertTwo() { }
function doAlertThree() { }
And then using jQuery like so:
$("ul li").each(function ()
{
switch($(this).attr("handler"))
{
case "doAlertOne":
doAlertOne();
break;
case ... etc.
}
});
Be pragmatic.
It's a bit hard to tell from your question, but perhaps you can use different jQuery selectors to set up different click behaviours? For example, say you have the following:
<div class="section-1">
<div></div>
</div>
<div class="section-2">
<div></div>
</div>
Perhaps you could do the following in jQuery:
$('.section-1 div').onclick(...one set of functionality...);
$('.section-2 div').onclick(...another set of functionality...);
Basically, decide based on context what needs to happen. You could also select all of the divs and test for some parent or child element to determine what functionality they get.
I'd have to know more about the specifics of your situation to give more focused advice, but maybe this will get you started.
I haven't don't really know about JQuery, but I do know that the DOJO toolkit does make highly unobtrusive Javascript possible.
Take a look at the example here: http://dojocampus.org/explorer/#Dojo_Query_Adding%20Events
The demo dynamically adds events to a purely html table based on classes.
Another example is the behaviour features, described here:http://dojocampus.org/content/2008/03/26/cleaning-your-markup-with-dojobehavior/