__defineSetter__ on innerHTML stops it from rendering - javascript

i'm trying to create a watch method for HTML elements, using __define[GS]etter__ when a property is changed. It reacts just fine when i set the value, but if the property listened to, is innerHTML, it somehow fails to render the given string. So basically, when im adding something to innerHTML it doesn't show.
Im using the watch method described in this previous question:
Watch for object properties changes in JavaScript
I could of cause just not listen to innerHTML changes, but i'm also wondering if the __defineSetter__ somehow prevents original handling of setting the value.
Thanks!

That shim code doesn't actually write-through: when you set a property, the value is only remembered on the watch-wrapper and not passed down to the underlying object. It's designed for pure JavaScript objects whose properties have no side-effects (like changing the DOM, in innerHTML's case).
Making it write-through would be a pain since there's no way to directly call the prototype's setter. You'd have to temporarily remove the property, write to the underlying property, then put it back in place.
However it's not really worth pursuing IMO. DOM Nodes are permitted to be ‘host objects’, so there is no guarantee any of the native-JavaScript object-property functions will work on them at all.
(In any case, adding new members onto the Object prototype is generally considered a Really Bad Idea.)
I could of cause just not listen to innerHTML changes
I think that's best, yes.

Ok update.
I found this page on MSDN, which has exactly what i need:
http://msdn.microsoft.com/en-us/library/dd229916(VS.85).aspx
But the Object.getOwnPropertyDescriptor way of doing things apparently only works in IE. Bummer. Any ideas would be appreciated.

I found another webpage with something that looked interesting, but i couldn't quite get it to do what i wanted:
http://www.refactory.org/s/recent/tag/accessors
I've decided to find a workaround for now, something with a timer that checks the attribute for changes and attribute change evnets for browsers that support that.
But if any one finds a solution for the question plz post :)

Related

Why $('div#my') is returning Object Reference instead of HTML Tag? [duplicate]

This question already has an answer here:
Why sometimes jQuery selector returns something like "a.fn.init"? [closed]
(1 answer)
Closed 6 years ago.
I don't know what happen to my Chrome browser, but all of sudden the behavior of doing $('div#my') in console is totally different from before. One time I've experienced this but later it somehow recovered, so I don't know how to reproduce it, and today it happened again.
Please watch the video:http://peaceevertvimg.org/jq.php.
In the video I do $('div#my') in two different browsers:
the first browser is not chrome but I believe it imitates Chrome so its behavior is what I expect and what I have almost always been experienced. Because currently my chrome is not working as expected so I have to use it to demonstrate my expection: when you do $('div#my)` you see directly the html TAG, and you can easily see the tag's html content, which is "something" in this case.
In contrast, in my chrome browser, the result is different, when I do $('div#my') I see an Object(n.fn.init), and I can't see the "something" immediately, which of course is very inconvenient. But before, I am pretty sure it was not like this, the behavior WAS exactly like that in the first browser.
The simple webpage in this video is http://peaceevertvimg.org/jquery.php, you can go test for yourself in chrome browser. And I am pretty sure most of you will see the first behavior. What happened to my chrome?(I've disabled all expansions and updated it to the latest version)
By the way, is "HTML Tag" and "Object Reference" the right words to describe these two different outcome?
*************Update*************
If the video is not sufficient to understand what I ask and what I want to fix, these two pictures may help.
Picture#1: This is the "normal" behavior I've expected:
Picture#2: This is the current behavior I am experiencing:
You can see the big differences, the first one is much more intuitive, revealing key information immediately, while the 2nd one is not, at least to me. What causes this problem and how do I go back to the first one?
$('div#my') doesn't return a DOM reference. It returns a jQuery wrapper around the found elements.
$('div#my')[0] would return a DOM reference. Or, forget jQuery and use:
document.getElementById("my");
...and you will get a DOM reference directly
Also, since there should/will only ever be one element with a given ID, it is unnecessary to use div#my, just use #my.
Assuming we have a <div id=someDiv>, and then we write:
console.log($("#someDiv"));
console.log($("#someDiv")[0]);
Chrome shows this:
In the first log, we see that the result is a jQuery object that contains one element (the div). In the second, we see the element directly.
Now, depending on what version of Chrome you have, you may see the first one reported simply as [Object object], but that doesn't change the underlying result.
From: Devx (http://www.devx.com/codemag/Article/40923)
Selectors let you select DOM elements so that you can apply
functionality to them with jQuery's operational methods. jQuery uses a
CSS 3.0 syntax (plus some extensions) to select single or multiple
elements in a document. You're probably already familiar with the CSS
syntax from HTML styling. Even if you're not, it's fairly easy to pick
up the key CSS selector features. I'll go as far as saying that jQuery
is the reason I really started to grok CSS. Using CSS syntax you can
select elements by ID, CSS class, attribute filters, or by their
relationship to other elements. You can even chain filter conditions
together. Look at this simple example, which selects all second-column
TD elements in a table using a simple selector: $("#gdEntries
td:nth-child(2)").
The jQuery Object: The Wrapped Set: Selectors return a jQuery object
known as the "wrapped set," which is an array-like structure that
contains all the selected DOM elements. You can iterate over the
wrapped set like an array or access individual elements via the
indexer ($(sel)[0] for example). More importantly, you can also apply
jQuery functions against all the selected elements. - See more at:
http://www.devx.com/codemag/Article/40923#sthash.l8Mo8CbH.dpuf
What you are seeing is said jQuery object returned by jQuery.fn.init().
What is going on is that jQuery() is being defined as jQuery.fn.init() which is another way to say jQuery.prototype.init() which is the selector function! What this means is that no one would call jQuery.fn.init() or jQuery.init() because jQuery() IS .init().
Some more info and a look at the jQuery code here: Help understanding jQuery's jQuery.fn.init Why is init in fn
As for a solution to your problem: https://chrome.google.com/webstore/detail/jquery-console-fix/jlmkkpkcgomkdpfhgjlpaaonhafnjgob?hl=en

jQuery and selectors: how can I make sure that there really is the element I'm looking for?

I'm no experienced JavaScript developer (I know quite a lot about Ruby, though), and so far, when I had to implement some lines of JS, it seemed enough to use jQuery and hack together something.
As far as I understand jQuery, it doesn't assume HTML elements to really be there, but it simply executes a query, and if there is a matching element (or many), some stuff is done with it. This works well for generic code which may want to apply some action to some elements on a page (which may be there or not), but when it comes to specific logic, it's a problem.
What do I mean with this? Let me give an example.
Let's suppose I have one single page with one single HTML element (with the ID '#my_element'). For exactly this page I have to run some JS code, and I have to be sure that it finds this element and does the things to it that I want.
Doing this with jQuery, I simply do something like $('#my_element').addTooltip(), which seems fine first: when I hover over the element, a tooltip is displayed.
Let's assume that some months later I already have completely forgotten about this JS script, and I change the ID of the element to something else. What happens? Nothing. I won't notice the problem with the missing tooltip until I stumble over it by accident.
So I wonder how I can make sure that my JS is really applied, which means: the required elements are found, the stuff is done to them, etc.
Is jQuery's philosophy the "wrong" tool for this? Do I need another framework? Maybe something more sophisticated pattern, e.g. something like MVC? I played with KnockoutJS before, and it seems that this may be better for this, as it's bound directly to elements using data-bind attributes, so it fits tighter on the code than jQuery does.
The comments mentioned always checking the .length property before performing actions on returned results (which is probably the best answer,) but in the case of an actual syntax error your statement that "nothing happens" isn't always true.
If you're using Chrome developer tools or a similar tool in another browser (firebug, etc.) you should see the error in the "Console"
You can also turn on javascript debugging for more information. When you call the "addTooltip()" on something which is null (the jQuery collection) you'll see an error pop up in the Console and may get an exception in the debugger.
This is one of the easiest ways to find errors in your client-side javascript.
You could add a specific plugin to verify the existence of a non-zero- length collection, and use that in the chain:
(function ($) {
$.fn.verify = function() {
if (this.length) {
return this;
}
else {
console.log("No elements found with supplied selector.")
}
}
})(jQuery);
$("#myElement").verify().addTooltip();
This does, of course, rely on the verify() plugin being manually applied, there is – to the best of my knowledge – no error-reporting built in to jQuery to automatically enable logging of invalid selectors, or reporting of selectors returning zero elements.

How does one figure out what piece of JavaScript changes a given HTML tag?

I often want to change some releatively minor detail about how JS changes the DOM, but I can never figure out which function in what script changes a given tag. How does one do this?
For example, on this page, I want whatever JS is adding the "selected" class to various a tags to also add it to the enclosing li tags. However, I have no idea how to figure out where this is taking place.
Clarification: As much as I'd like an answer to my current, specific conundrum, I'd much rather be taught how to figure it out myself.
CLARIFICATION:Is there a way to point at a certain object in the DOM and find out what script(s) are/were accessing/modifying that object? In other words "watch" that object for JS access/modification.
What you need is DOM breakpoints in WebKit's Developer Tools.
They're designed for tracking DOM mutation events - such as change of an attribute of an element (which is your case), element removal, or addition of subelement. You can refer to tutorial in DevTools documentation.
In basic cases you might want to use grep for searching the strings such as "selected" in your code.
I’m not aware of any debugging tools that’ll tell you when a DOM element is being acted upon by a script.
(If anyone knows of any, dear lord please tell me about them — I’m a freelancer, so I spend most of my working days trying to figure out old, knotty DOM-manipulating JavaScript that someone else wrote.)
You basically have to search through every bit of JavaScript file included in the page, and identify lines that might be taking the action you’re seeing.
In the case of a class name being added to an element, an obvious search is for the class name itself, although that’s not guaranteed to work. E.g.
el.className = el.className + 'sel' + 'elected'
If jQuery is in use, I’d definitely search for addClass.
Once you think you’ve found the right line, then if you have access to the JavaScript code, you can change it and see if your change takes effect.
(And, because view source is still a part of the web, you can get access to the code by saving it all to your computer.)

Unpredicted behavior of using non-unique IDs

When people are saying that using identical id's for different DOM elements is wrong, I totally agree. I mean, there is no even something to discuss.
But what is actually meant by the phrase "if you will have several eponymous ids on the page, that doesn't guaranteed to work"?
What actually does not guaranteed to work? We can treat ID as a regular attribute, thus, we can find all divs that document.querySelectorAll('[id="container"]'). Accessing through getAttribute/setAttribute should work as well. If we are trying to fetch an element via document.getElementById - well, I haven't tested, but most probably selector engine will return first element it find traversing the tree. I can imagine this can not be guaranteed. What else?
CSS will work pretty fine - #container {background-color: "red"} will paint with red all found containers (or am I wrong). Can somebody show me where in standard spec such behaviour is not guaranteed?
So, what is actually not guaranteed? Once again, I do acknowledge the fact that using same IDs is wrong. Neither do I want discuss perfomance issues of applying id-heavy css rules. The question is about something which is quite similar to what C/C++ programmers call "unpredicted behavior".
UPD: If it sounds hard or even stupid for you, then well, just provide an examples of unpredictable ID related behavior in specific browser. At least, as for me, it is more useful answer than "well, anything is not guaranteed, how can not you get it!".
An implementation would be within the spec if it refused completely to work with documents that contain duplicate ids, or ignored the multiply-used id in all of the elements that claim it, or returned a random of the elements from getElementById. It could even be a different random element in each call.
Can somebody show me where in standard spec such behaviour is not guaranteed?
That's not how it works. If it's not guaranteed, then everywhere in the spec is where it's not guaranteed. It's only guaranteed if somewhere in the spec there's an explicit guarantee you can point to. Otherwise, there's no guarantee in the spec, which means that it's not guaranteed.
The spec says that ID's are supposed to be unique.
That means that the browser itself has no obligation to implement code that can support multiple non-unquie IDs. It can assume when it builds the DOM model that ids are unique and are usable as keys. They may work in some browsers, today. But maybe tomorrow they won't. Just because they happen to function in the browsers you have tested, doesn't mean they will in future versions, or they behave as such in a different non-repeatable manner.
Maybe the first time you load a page on a monday document.getElementById might return the first element, if it's after 5pm on a tuesday and it's on an SSL site, then maybe document.getElementById throws an exception. Maybe a new release of firefox doesn't apply css attributes to anything past the first occurance of the id. Who knows. The browser developers don't have to care, that is what "not guaranteed to work" means.
Here is a jsfiddle showing some selector quirks: http://jsfiddle.net/DmEmJ/
Quoth the spec:
id = name [CS]
This attribute assigns a name to an element. This name must be unique in a document.
If you want a non-unique handle, use classes. That's what they are for.

How to find the snippet of JavaScript that modifies an element?

The page I'm trying inspect has a hidden <input type="hidden" name="Foo" value="123 /> element on a page, where Javascript/AJAX modifies the value. I'm trying to find where on earth in Javascript is the code that modifies this value from time to time.
Is there a tool that could help me find the places in javascript that use/modify that element? Does Firebug provide this, if so, how?
Note: If tried looking for "Foo" in the code, but I haven't found any matching titles. There's JSON and Mootools loaded, +application specific code, which results several thousands lines of code. The element is probably accessed indirectly.
Firebug 1.5 will have "Break-on-Modify" on the HTML panel. See http://getfirebug.com/doc/breakpoints/demo.html#html - Break on DOM (HTML) Mutation Events.
How do you know that the javascript is modifying this value? Since it looks you already know when it's called (since you know it changes), I would suggest a breakpoint in Firebug in the first event that initiates the changing (probably an onclick attribute in other element).
It's kind of hard telling you a "generic" way of knowing where in javascript it's changing Foo's value since there are a lot of different approachs, different libraries, each one with it's syntax.
For example, if you tried searching "Foo" and didn't find it, the script may be traversing the DOM and changing the input's value as a "first child of something". I would try to search for names or ids of input's parent elements and understand the code from there.
I usually just try to understand the javascript logic from every script I use with Firebug's debugging techniques - but just on the script that uses the libraries.
If Firebug doesn't let you define breakpoints on setting some value, you could insert something like this in the page (Firefox-only):
$("textarea")[0].__defineSetter__("value", function(val) {
alert("called");
})
And either breakpoint on the function in Firebug or use console.log or whatever to dump the stack to the firebug console.
I remember seeing somewhere a presentation on Firebug plans, which included a section on various kinds of breakpoints to be supported, but I can't find a link to it right now.
[edit] The above is for the case the value is set by assigning to the value property: .value = .... If you need to catch the moment an attribute is changed (.setAttribute("value", ...)), you can use DOM mutation listeners.

Categories

Resources