How JQuery objects assigned to a variable detect changes? - javascript

(First of all sorry for my English) I can understand assigning JQuery objects that found by JQuery selectors, to a variable has better performance then using JQuery Selectors every time. The part that i cannot understand is how JQuery detects changes that are not manipulated by JQuery? Here is an example:
<div id="divState">First State</div>
$(document).ready(function () {
var testElement = $("#divState");
alert(testElement.text());//alerts "First State".
document.getElementById("divState").innerHTML = "Second State";//Div has changed outside of the JQuery object.
alert(testElement.text());//alerts "Second State"??? How a variable detects changes.
});

Well, it knows, but it doesn't know . . .
As Blazemonger points out, when you create a jQuery object, one of the items in the object is, essentially, just a pointer to the actual DOM element in the page. So, like you show in your example, any time you inspect the properties of that object, it will inspect the element and show you whatever they currently are. If they change in between checks, you will see the difference.
However, jQuery is not 100% smart . . . if you were to change something fundemental to the selector, it is not smart enough to know to update the collection of objects, without re-selecting them. For example, look at this HTML:
<div id="container">
<div class="similarDivs">Div 1</div>
<div class="similarDivs">Div 2</div>
<div class="similarDivs">Div 3</div>
</div>
If you run the following code against it:
var $mainGroup = $("#container");
var $subGroup = $mainGroup.find(".similarDivs");
console.log($subGroup);
. . . your console would show: Object[div.similarDivs, div.similarDivs, div.similarDivs]
But, if you were to follow that up with this code:
$mainGroup.children(":eq(0)").removeClass("similarDivs");
console.log($subGroup);
. . . your console would show: Object[div, div.similarDivs, div.similarDivs]
It is smart enough to see that the 1st div is no longer tagged with the "similarDivs" class, but it is not smart enough to know that, technically, that means that it should no longer be part of the $subGroup selection group. Again, this is because the selector created a bunch of jQuery objects that point to all of the DOM elements that matched the selection criteria, at a single point in time.
The only way that you could get $subGroup to reflect the change in its collection is by re-running the selector:
$subGroup = $mainGroup.find(".similarDivs");
console.log($subGroup);
. . . resulting in: Object[div.similarDivs, div.similarDivs]
One of the biggest reasons that this is so important (apart from knowing that when you use selectors :) ), is because Javascript does NOT behave that way . . . if you were to write a similar set of functionality in JS, you would get different results:
var mainGroup = document.getElementById("container");
var subGroup = mainGroup.getElementsByClassName("similarDivs");
console.log(subGroup);
mainGroup.children[1].className = "";
console.log(subGroup);
That code would give you:
HTMLCollection[div.25dd58, div.25dd58, div.25dd58]
HTMLCollection[div.25dd58, div.25dd58]
. . . without needing to "re-select" the elements (note: it is also returning an HTMLCollection, not a jQuery Object, which clues you in to the difference in behavior).

As I understand it, the jQuery object contains the DOM node, which is itself a live object. So changing the properties of the DOM node is reflected in the jQuery object.
If you were to .clone() the jQuery object, you'd get the behavior you're expecting:
$(document).ready(function() {
var testElement = $("#divState").clone(); // copy the object and store it
alert(testElement.text()); //alerts "First State".
document.getElementById("divState").innerHTML = "Second State"; //Div has changed outside of the JQuery object.
alert(testElement.text()); //alerts "First State" again
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divState">First State</div>

jQuery is NOT a different programming language. Its a library built on Javascript.
testElement.text() do not detect any change it simply picks the text of testElement and display to alert

I am fairly certain that testElement is just instructions on how to find the DOM element using good old JavaScript, which is faster than finding it via the jQuery selectors.
So every time you work with it, it finds it anew.
Please correct me if I am wrong, that is just an assumption I have based on experience rather than knowledge.

Related

How to change InnerHtml to an attribute

Can some one show how I can change the InnerHTML of the titles class to be the same as the alt attribute. For the actual website jarretonions.co.za
Thanks
$(document).ready(function() {
$(".pic").on("click", function() {
$(".modal").show();
var srclong = $(this).attr("src");
var srcshort = srclong.split("_");
var srcextension= srclong.split(".");
$(".modal img").attr("src", srcshort[0]+'.'+srcextension[1]);
************is it something like this********
var title = $(this).attr("alt");
$(".modal span").InnerHTML= title;
OR
document.getElementByClassName('titles').innerHTML = title;
})
+
echo
"<div class='art'>
<img class='pic' src='img/".$row["name"]."_tnail.jpg'
alt='".$row["name"]." • ".$row["year"]." • ".$row["type"]."'
height='auto' width='100%'/>
<div class='modal'>
<img class='big'/>
<span class='titles'></span>
</div>
</div>"
;
Since you're using JQuery, you can select those elements using $(".title") and change them directly. Something like so:
$(document).ready(function() {
$(".pic").on("click", function() {
$(".title").text( $(this).attr("alt") );
})});
Here's a fiddle: https://jsfiddle.net/wmjtfLja/1/
Note that if you have more than one element of class .title, they will all change. So you may want to select the title element by id or by relative path from the clicked image.
Realizing in advance, the danger of providing an answer that is not (superficially) fully aligned with the question, I was struck by the comment from melpomene, whom I initially thought was refering to things not existing in jquery.
melpomene is 100% correct, since getElementByClassName does not exist.
The correct syntax is getElementsByClassName.
Having said that, helloworld is also correct (syntax errors aside), since loading jquery for every little task is really redundent, and one can manipulate by class with little more half a dozen lines of pure javascript.
But, getting elements by class has dangers, since the return is a 'live' array.
For example, with dylan's original question, getting by class is only useful to return the first instance (the array length is just a guide of how many elemnts it applies to). Therefore, for dylan to make changes as he proposed, each requires its own button. (which also means, michael that I believe you are incorrect when you say it will affect all elements with same class name - oth, you are fully correct in noting that one should inpsect for other values (or change the class name) when running loops on the attribute).
Consider the following (on the fly class change);
function otf_cls_change(cls_original,cls_replace){
var a=document.getElementsByClassName(cls_original);
l=a.length;
if (l==0){return 0;}
do {
a[0].setAttribute('class',cls_replace);
a=document.getElementsByClassName(cls_original);
l=a.length;
} while (l>0);
}
This is effective for changing class names on the fly.
But, if we modify the code and
//change this a[0].setAttribute('class',cls_replace); // to
a[0].innerHTML='this_html';
It will cause the browser to hit an endless loop.
Why? because the live array returned by ElementByClass will only process the first item (even if you try to loop the array).
Therefore, while changing the class on the fly is fun and very do-able, I'd strongly suggest that using it to change any attrib that is not specific to the class id is a bad idea.
Changing the class attrib in conjunction with another attrib is fine.
For example,
a[0].innerHTML='this_html'; //do this first
a[0].setAttribute('class',cls_replace); //then this
The above will work to loop class defined elements.
On a point of massive personal hypocrisy, I do get annoyed when people ask for pure javascript solutions, and then some wing nut chimes in with jquery. I guess I'm doing the opposite here, since evidently, the question was jquery related, and here I am throwing out pure javascript. Sorry bout that.
btw, dylan, good luck with it. glad you bit back on the negative comment. Too many people here are terrified of offending, and wind up get bullied.
hth,
Gary

Jquery, cannot access css properties of dynamically generated element

I am using jQuery to append elements to a div, and all works fine.
var new_div = $('<div>My stuff</div>');
new_div.appendTo("#container");
However, I'd like the div to appear by fading in, instead of abruptly.
I notice though that I get an error when I try to access graphic properties on my dynamically generated element. So this, for example fails:
new_div.hide().fadeIn();
The console reports the following error:
TypeError: jQuery.curCSS is not a function
Do I understand this correctly, that this fails because current css properties are not defined for the dynamically generated element? Or what else can be goingg wrong?
Important edit
Additional checking and working on this pointed out to a complete misunderstanding from my part. This has nothing to do with the fact that the element was dynamically generated. I got the same thing by calling fadeIn() on whatever element.
I sincerely apologize!
I still didn't get, though, why this happens
Adding elements to the DOM takes some time, miliseconds maybe, but it's still a reason for jquery not be able to find the element.
This process might be even slower if the DOM is a large html page.
Write your code like this:
var new_div = $('<div>My stuff</div>');
new_div.appendTo("#container");
setTimeout( function(){
new_div.hide().fadeIn();
} , 150); // 100 could be also good
It might be enough time for jquery to catch the element.
I would add an id to keep track of all elements I'm creating (just my preference, but it makes it easier to code it).
var new_div = '<div id="myNewDiv1" style="display:none;">My Styff</div>'
$('body').append(new_div);
$('#myNewDiv1').fadeIn();
It does seem to be a compatibility question, although I wasn't able to figure out exactly why and how to fix it.
Adding this code fixes the problem though:
jQuery.curCSS = function(element, prop, val) {
return jQuery(element).css(prop, val);
};

Get dynamic text from selected object - (by ID and "active" class) - jQuery

My main mission: Is to get the text of the next and the previous objects to the chosen object - To display the image (and its titles) Previous & Next.
Before that I have a problem: to get text of a selected object, from an index to a variable.
The problem: Every time I pick a random object, the variable does not change but the text is added to the existing text in the index.
I made a DEMO, would appreciate your help.
$(document).ready(function hintProject(){
$('#nextProject, #prevProject').click(function(){
subtitle = null;
subtitle = $('#client-sub.active').justtext();
$('#next_target_title').text(subtitle);
alert (' text::: ' + subtitle );
});
});
It looks like jQuery simply can't find the objects you're specifying. I don't think the problem is with the snippet in the question. I think the problem is with your document ready function.
To debug, try simplifying your problem by cutting out all of the additional complexity of the setup script and just set up an HTML page that is in the state you want. It's much easier to understand 1 problem than 2 or more.
Also, try simplifying how you're specifying an active item: a single class on the portfolio item would make your life easier. Then you can specify css and such based on the parent instead of adding multiple classes to multiple things inside the each portfolio item.

Create drop-down list using JavaScript instead of HTML

I have the following code that creates and deletes text boxes using javascript:
http://jsfiddle.net/JpYGg/8/
What I am aiming to do is infact create a set of three drop-down lists using this functionality instead of creating a textbox.
The code for the three drop-downs is shown here:
http://jsfiddle.net/MWH99/
I am a bit stuck as to how to achieve this. I added in the "dropdown" div and what I was thinking is to get the innerHTML of this div in order to use that to create the three lists every time?
The other question I have is how to have it so that these are generated by the javascript instead of an HTML one AND a JavaScript version.
Thank you for any help.
Martin
EDIT
I have the buttons working to create the next row of 3 drop-downs but they do not function the way that the original does, the parent drop-downs use javascript to identify the selection in the first drop-down in order to update the other two whereas the cloned ones lose this functionality.
Code cna be found here:
http://pastebin.com/pt1wef76
Original drop downs use dropdown.js which is http://pastebin.com/bDLpFWJY
Why not use a javascript library like jQuery for example. Would make this and many other things much easier. Could achieve what you want like this:
$('body').append('<!-- ANY HTML GOES HERE -->')
There's two basic approaches; create all of the elements in JavaScript, or copy a part of the DOM (some HTML) over and over.
People often put HTML in script tags (see jQuery Templating, for example), and then get the innerHTML of the tag and use that. For example,
<script type="text/plain" id="template">
<!-- HTML that you want to duplicate in here -->
</script>
<div id="contentcontainer">
</div>
...
<script type="text/javascript">
var addAnother = function( ) {
$("#contentcontainer").append(
$("#template").html()
);
};
</script>
This example makes use of jQuery primarily because jQuery is a lot less verbose and easier to read, but you certainly don't have to use jQuery. Here, the addAnother function will copy the HTML from #template and append it into #contentcontainer.
In your attempt above, you probably meant $('body').append($('#dropdown')); '#dropdown' is just a string, $('#dropdown') returns the element (or elements) with id="dropdown".

Accessing created DOM elements

I have code to create another "row" (div with inputs) on a button click. I am creating new input elements and everything works fine, however, I can't find a way to access these new elements.
Example: I have input element (name_1 below). Then I create another input element (name_2 below), by using the javascript's createElement function.
<input type='text' id='name_1' name="name_1" />
<input type='text' id='name_2' name="name_2" />
Again, I create the element fine, but I want to be able to access the value of name_2 after it has been created and modified by the user. Example: document.getElementById('name_2');
This doesn't work. How do I make the DOM recognize the new element? Is it possible?
My code sample (utilizing jQuery):
function addName(){
var parentDiv = document.createElement("div");
$(parentDiv).attr( "id", "lp_" + id );
var col1 = document.createElement("div");
var input1 = $( 'input[name="lp_name_1"]').clone(true);
$(input1).attr( "name", "lp_name_" + id );
$(col1).attr( "class", "span-4" );
$(col1).append( input1 );
$(parentDiv).append( col1 );
$('#main_div').append(parentDiv);
}
I have used both jQuery and JavaScript selectors. Example: $('#lp_2').html() returns null. So does document.getElementById('lp_2');
You have to create the element AND add it to the DOM using functions such as appendChild. See here for details.
My guess is that you called createElement() but never added it to your DOM hierarchy.
If it's properly added to the dom tree you will be able to query it with document.getElementById. However browser bugs may cause troubles, so use a JavaScript toolkit like jQuery that works around browser bugs.
var input1 = $( 'input[name="lp_name_1"]').clone(true);
The code you have posted does not indicate any element with that name attribute. Immediately before this part, you create an element with an id attribute that is similar, but you would use $("#lp_1") to select that, and even that will fail to work until you insert it into the document, which you do not do until afterwards.
var input1 = $( 'input[name="lp_name_1"]').clone(true);
should be
var input1 = $( 'input[#name="lp_name_1"]').clone(true);
Try that first, check that input1 actually returns something (maybe a debug statement of a sort), to make sure that's not the problem.
Edit: just been told that this is only true for older versions of JQuery, so please disregard my advice.
Thank you so much for your answers. After walking away and coming back to my code, I noticed that I had made a mistake. I had two functions which added the line in different ways. I was "100% sure" that I was calling the right one (the code example I posted), but alas, I was not.
For those also experiencing problems, I would say all the answers I received are a great start and I had used them for debugging, they will ensure the correctness of your code.
My code example was 100% correct for what I was needing, I just needed to call it. (Duh!)
Thanks again for all your help,
-Jamie

Categories