Best javascript questions in June 2012

Why are my balls disappearing?

145 votes

Pardon the funny title. I've created a little graphic demo of 200 balls bouncing and colliding, both against the walls and each other. You can see what I have currently here: http://www.exeneva.com/html5/multipleBallsBouncingAndColliding/

The problem is that whenever they collide with each other, they disappear. I'm not sure why. Can someone take a look and help me out?

UPDATE: Apparently the balls array has balls with coordinates of NaN. Below is the code where I push balls to the array. I'm not entirely sure how the coordinates are getting NaN.

// Variables
var numBalls = 200;  // number of balls
var maxSize = 15;
var minSize = 5;
var maxSpeed = maxSize + 5;
var balls = new Array();
var tempBall;
var tempX;
var tempY;
var tempSpeed;
var tempAngle;
var tempRadius;
var tempRadians;
var tempVelocityX;
var tempVelocityY;

// Find spots to place each ball so none start on top of each other
for (var i = 0; i < numBalls; i += 1) {
  tempRadius = 5;
  var placeOK = false;
  while (!placeOK) {
    tempX = tempRadius * 3 + (Math.floor(Math.random() * theCanvas.width) - tempRadius * 3);
    tempY = tempRadius * 3 + (Math.floor(Math.random() * theCanvas.height) - tempRadius * 3);
    tempSpeed = 4;
    tempAngle = Math.floor(Math.random() * 360);
    tempRadians = tempAngle * Math.PI/180;
    tempVelocityX = Math.cos(tempRadians) * tempSpeed;
    tempVelocityY = Math.sin(tempRadians) * tempSpeed;

    tempBall = {
      x: tempX, 
      y: tempY, 
      nextX: tempX, 
      nextY: tempY, 
      radius: tempRadius, 
      speed: tempSpeed,
      angle: tempAngle,
      velocityX: tempVelocityX,
      velocityY: tempVelocityY,
      mass: tempRadius
    };
    placeOK = canStartHere(tempBall);
  }
  balls.push(tempBall);
}

Your error comes from this line initially:

var direction1 = Math.atan2(ball1.velocitY, ball1.velocityX);

You have ball1.velocitY (which is undefined) instead of ball1.velocityY. So Math.atan2 is giving you NaN, and that NaN value is propagating through all your calculations.

This is not the source of your error, but there is something else that you might want to change on these four lines:

ball1.nextX = (ball1.nextX += ball1.velocityX);
ball1.nextY = (ball1.nextY += ball1.velocityY);
ball2.nextX = (ball2.nextX += ball2.velocityX);
ball2.nextY = (ball2.nextY += ball2.velocityY);

You don't need the extra assignments, and can just use the += operator alone:

ball1.nextX += ball1.velocityX;
ball1.nextY += ball1.velocityY;
ball2.nextX += ball2.velocityX;
ball2.nextY += ball2.velocityY;

Why does ",,," == Array(4) in Javascript?

92 votes

Boot up your interpreter/console and try the comparison

> ",,," == Array(4)
True

Why? At first I thought maybe since you could think of ",,," as an array of four characters with a '\0' terminating slice, that might be why, but

"..." == Array(4)

Returns "False". So... why? I know it's some idiosyncratic bit of duck typing in Javascript, but just curious what underlines this behavior. Gleaned this from Zed Shaw's excellent presentation here btw: http://vimeo.com/43380467

Thanks,

Nathan

Because the right hand operand is converted to a string and the string representation of Array(4) is ,,,:

> Array(4).toString()
  ",,,"

If you use the array constructor function and pass a number, it sets the length of the array to that number. So you can say you have four empty indexes (same as [,,,]) and the default string representation of arrays is a comma-separated list of its elements:

> ['a','b','c'].toString()
  "a,b,c"

How the comparison works is described in section 11.9.3 of the specification. There you will see (x == y):

8. If Type(x) is either String or Number and Type(y) is Object,
return the result of the comparison x == ToPrimitive(y).

(arrays are objects in JavaScript)

and if you follow the ToPrimitive method you will eventually find that it it calls toString.

Why does ("foo" === new String("foo")) evaluate to false in JavaScript?

73 votes

I was going to start using === all the time when comparing string values, but now I find that

"foo" === new String("foo")

is false, and same with this:

var f = "foo", g = new String("foo");
f === g; // false

Of course:

f == g; // true

So is it recommended to always use == for string comparison, or always convert variables to strings before comparing?

"foo" is a string primitive. (this concept does not exist in C# or Java)

new String("foo") is boxed string object.

The === operator behaves differently on primitives and objects.
When comparing primitives (of the same type), === will return true if they both have the same value.

When comparing objects, === will return true only if they refer to the same object (comparing by reference). Thus, new String("a") !== new String("a").

In your case, === returns false because the operands are of different types (one is a primitive and the other is an object).


Primitives are not objects at all.
The typeof operator will not return "object" for primitives.

When you try to access a property of a primitive (using it as an object), the Javascript language will box it to an object, creating a new object every time. This is described in the specification.

This is why you cannot put properties on primitives:

var x = "a";
x.property = 2;
alert(x.property) //undefined

Each time you write x.property, a different boxed String object is created.

Working with data in jQuery

14 votes

I would like to ask for more an opinion than a question: What would the community recommend to do when you must do a webpage with lots of data, for example, a products listing, that should have some functionality like buy (adds to cart), sorting, etc. if you have to manipulate the data of the current product - price, title, image, link and other attributes? How you do it in your projects?

For example we have a page with dozens of products, each of them has attributes: price, title, description, image(URL), link(URL). How would you store the data to use it on some user interaction? Personally, I've done it by just inserting each of the attribute in tags, something like:

<div class="product" data-product_id="123">
  <div class="pr_title">Title</div>
  <div class="pr_body">Body</div>
  <div class="pr_img"><img src="http://www.www.www/img.png"></div>
  <div class="pr_link"><a href="http://www.stackoverflow.com/">Buy!</a></div>
</div>

This way I have my html structure for presentation and I worked with data in jQuery by something like:

var url = $('.product').find('.pr_link').find('a').attr('href');

But when the project got big and there were 10-15 more attributes added to each element, getting data from current product got pretty complicated and the code became mostly unreadable.

I thought of using same structure, but to keep data in some object like:

var products = {
    1: {
        title: "abc",
        description: "lorem ipsum",
        price: 25.19,
        img: "http://www.www.www/img.png",
        link: "http://www.stackoverflow.com"
    }
}

and keep markup as simple as possible, only using elements and styles needed for design with css:

<div class="product" data-product_id="123">
  <div class="title">Title</div>
  <div>Body</div>
  <img src="http://www.www.www/img.png">
  <a href="http://www.stackoverflow.com/">Buy!</a>
</div>

so onClick I would need to retrieve the id of the product and query it in our object "products":

var url = products[id].title;

While this is the most convenient way to work with it requires a new object.

Another idea was to keep all data in data- attributes of the parent div element like:

<div class="product" data-product_id="123" data-title="abc" data-body="Body">

but for much as I know jQuery doesn't work with data attributes well (natively).

So what are your suggestions? Maybe you have some even better ideas to share.

P.S. I tried to find some information on the subject, but most likely failed to find the way to formulate it well so I found nothing about it. If there are links or even similar questions on stack exchange sites, please feel free to post them. Thank you in advance!

You can use HTML5 data attribute to store products data, as you have several properties of products to associate with each product block, you can JSON encode the object and assign to the top element, and then can access that on user interaction on that element or any child element.

var product = {
    title: "abc",
    description: "lorem ipsum",
    price: 25.19,
    img: "http://www.www.www/img.png",
    link: "http://www.stackoverflow.com"
};
$(selector).data('product',JSON.stringify(product));

then to retrieve the object you can do on any event's callback

$product = $.parseJSON($(elem).data('product'));

In fact both facebook and twitter used data attributes to store associated data with tweets and stories. For example here goes some html of a FB story

<li data-ft='{"qid":"5757245005920960301","mf_story_key":"7164261693049558180"}'
 id="stream_story_4fe5d7d51bc415443080257">

You can see facebook is storing JSON encoded data into the data-ft attribute.

Similarly an example of a Twitter tweet html

<div data-tweet-id="216534496567230464" data-item-id="216534496567230464" 
data-screen-name="onimitch" data-user-id="123682011" data-is-reply-to="">

So twitter is saving associated data for a tweet into different attributes like data-tweet-id, data-user-id.

So As they both handle's a lot amount of data, I think You can also use either of the method to save your data without any performance issue.

If you store data with individual keys then be aware of the automatic data conversion that .data() does as @nnnnnn has already mentioned in comment.

Demo With .data() : http://jsfiddle.net/joycse06/vcFYj/

Demo With .attr() : http://jsfiddle.net/joycse06/vcFYj/1/

Understanding "this" keyword

14 votes

In this commit there is a change I cannot explain

deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );

becomes

deferred.done( arguments ).fail( arguments );

AFAIK, when you invoke a function as a member of some object like obj.func(), inside the function this is bound to obj, so there would be no use invoking a function through apply() just to bound this to obj. Instead, according to the comments, this was required because of some preceding $.Callbacks.add implementation.

My doubt is not about jQuery, but about the Javascript language itself: when you invoke a function like obj.func(), how can it be that inside func() the this keyword is not bound to obj?

My doubt is not about jQuery, but about the Javascript language itself: when you invoke a function like obj.func(), how can it be that inside func() the this keyword is not bound to obj?

Well, the only way this is possible is if obj.func references a bound function, then it doesn't matter how you call it. In that case it doesn't matter how you call the function, whether you do obj.func(), func(), func.call({}), func.apply({}) doesn't matter at all. I'm not sure how the commit is related to this, however.

To clarify, I am answering the quoted question interpreted as:

Given a call signature like: obj.func(), how is it possible that this is not obj inside the called function for the call?

Why does the same RegExp behave differently?

12 votes

Possible Duplicate:
Interesting test of Javascript RegExp
Regular expression test can't decide between true and false (JavaScript)

Example of issue. When ran inline the results are as I would expect. But when stored as a variable it skips the middle span element.

// Inline RegExp
function getToggleClasses() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    if (/toggler/g.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Inline: " + toggler.length;
}

// Variable
function getToggleClasses2() {
  var toggler = [],
      elements = document.getElementsByTagName("*"),
      tester = /toggler/g,
      i=0,
      len = elements.length;

  for (i; i < len; i++) {
    if (tester.test(elements[i].className)) {
      toggler.push(elements[i]);
    }
  }

  document.getElementById('results').innerHTML += "<br />Variable: " + toggler.length;
}
​

Mark up:

<span class="toggler">A</span>
<span class="toggler">B</span>
<span class="toggler">C</span>

Given: I understand there is no reason to use a RegExp to do this comparison and I also understand how great libraries such as jQuery are. I also know that the g is not needed in this case.

I can't understand why these two methods should ever return different results.

RegExp instances are stateful, so reusing them can cause unexpected behavior. In this particular case, it's because the instance is global, meaning:

that the regular expression should be tested against all possible matches in a string.

That's not the only difference caused by using g, however. From RegExp.test @ MDN:

As with exec (or in combination with it), test called multiple times on the same global regular expression instance will advance past the previous match.


Remove the g flag, or set lastIndex to 0 (thanks, @zzzzBov).

How do you detect if an html element can append child nodes?

12 votes

I created a custom jquery event called 'loading' in my application. I want to append a masking element with a spinner, when this event is triggered. I can figure out that part without problems. However, some elements (images, form inputs, etc..) cannot append child elements. I need to be able to detect if the target of this event can receive child elements. If it cannot, then I will add the spinner & mask to it's parent element.

You have to check the name:

/*global $, jQuery */

function isVoid(el) {
    var tags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
                 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'],
        i = 0,
        l,
        name;

    if (el instanceof jQuery) {
        el = el[0];
    }

    name = el.nodeName.toLowerCase();

    for (i = 0, l = tags.length; i < l; i += 1) {
        if (tags[i] === name) {
            return true;
        }
    }
    return false;
}

And use it like this:

var el = document.getElementById('el'),
    elj = $('#el');

if (!isVoid(el)) {
    // append
}

Stack vs. Heap in Javascript?

12 votes

I'm trying to write a web-page for which I need to shovel around several 100MB of data in JavaScript (Let's not discuss the sensibility of this, though...). With different browsers I run into "maximum call stack size exceeded" errors at different data amounts.

Can I fix this issue by going through my code and trying to move local variables inside functions into a more global scope to try to get them to be allocated on the heap instead of the stack? Or do these concepts not exist in JavaScript? (As far as I know, I don't have any major recursive loops in my data, so it really is a couple of huge strings / number arrays that seem to be causing the error)

If this isn't possible, are there ways to ask the browser to reserve more memory?

There's no separation of memory into stack/heap in Javascript. What you seeing could be one of following:

  1. Recursion that ran too deep. In that case you'll need to review your algorithm to make it more iterative and use less recursion so you don't hit call stack limits imposed by browsers.
  2. If your algorithm do not have deep recursion, this might still be just a deep enough call, considering that your code is generated.
  3. Lastly, some engines may allocate function arguments and scoped named variables on some sort of internal stack for fast lookup. If you (or automatically generated code) happens to literally use thousands of local variables or arguments in function, this may overflow engine-specific limits as well.

jQuery data() returns undefined, attr() returns integer

11 votes

I have the following code:

alert($embellishment.data("embellishmentId"));
alert($embellishment.attr("data-embellishmentId"));

The first alert returns undefined, whereas the second alert returns an integer, 3.

-- SEE DEMO --

I'm using jQuery version 1.7.2 (data was added with version 1.4 I believe)

Why is this? Should I be using data() at all if its not returning the right values?

OK. I found the problem by interpreting jQuery docs.

When you write:

$embellishment.data("embellishmentId");

it is handled by jQuery as compound attribute:

<div data-embellishment-id="3"></div>

So, to solve the problem you can use lower case in the data key otherwise it just addresses the different attribute.

<!-- HTML -->
<div data-embellishmentid="3"></div>

// JavaScript
$embellishment.data("embellishmentid");

Rendering box shadow around unconventional shapes with HTML/CSS

11 votes

I'm currently working on a little project in which I'm trying to create a venn diagram representing additive colors. I've started with three circles (border-radius: 50%;) and used a combination of statically-position elements with hidden overflow to create some of the more complex shapes where the circles overlap. You can see what I currently have here:

http://jsfiddle.net/GjvEE/

One feature I'd like to add is the addition of a colored box-shadow around the shape currently being moused-over. The unique challenge I'm facing is presented by the nesting of the elements with hidden overflow, and the need to create 'faux-edges' along which to render the box shadow for each section of the diagram. I've considered the option of simply scrapping this approach and creating the shapes via SVG, but I'm interested to see if any of you have any clever ideas for building this sort of interaction into more complex shapes using traditional HTML and CSS3 alone.

Thanks in advance!

How about using CSS's :after to generate new circles behind the others and use a radial gradient background that fades to transparent?

I've done quick, basic implementations for Webkit on the red and blue circles here. Note the :hover:after style definitions. http://jsfiddle.net/stevelove/2hpwp/

jQuery: $(this) vs. this.$()

11 votes

In Ember.js's docs, they have a jQuery code snippet with the following syntax:

this.$().button();

Is this snippet only turning this into a jQuery object so that the jQuery UI .button() function can be called on it?

Would this snippet be identical?

$(this).button();

The source code explains this as follows:

/**
    Returns a jQuery object for this view's element. If you pass in a selector
    string, this method will return a jQuery object, using the current element
    as its buffer.

    For example, calling `view.$('li')` will return a jQuery object containing
    all of the `li` elements inside the DOM element of this view.

    @param {String} [selector] a jQuery-compatible selector string
    @returns {Ember.CoreQuery} the CoreQuery object for the DOM node
  */
  $: function(sel) {
    return this.invokeForState('$', sel);
  },

So to answer your question: no it's not the same as $(this), which would wrap the ember view instance in a jQuery object...

Does javascript event handling occur inside or outside the program flow?

10 votes

This question is related to Javascript event handling and flow control, but it is one step beyond. The question that remains unanswered is: when an event is fired and control is returned to the browser, could the browser decide to handle other events first (fired by other scripts or user action) (A), or will it always handle my event directly (B)?

Does javascript event handling occur outside (A) or inside (B) the program flow? The question is important, because in case (B) you can rely on the fact that nothing has been changed between firing the event and the event handler, while (A) gives no guarantees whatsoever.

My first guess is (B), how else could stopPropagation() and preventDefault() work? But giving it a second thought, it is no hard evidence.

A real-life example of this problem. I am modifying a rich text editor (hallo), and I want it to have these specs:

  • clicking on an editable text (#txt) will activate the editor, and clicking outside #txt will deactivate it. hallo uses blur and focus events on #txt to achieve this.
  • Activating the editor opens a toolbar, mousedown on the toolbar (but not on a button) will set a flag that prevents the blur event on #txt to deactivate the editor. The toolbar will return focus to #text.
  • mousedown on a toolbar button should also prevent deactivating the editor, but it should first wait till the click event, perform its action and then return focus to #txt. Some actions are immediate (bold or italic), while others need extra user input (selecting from a dropdown).
  • Some of these buttons open a dialog.
  • ...And I want all these elements (editor, toolbar, dialog) to be modular and easily extendable.

Now in most cases when you close a dialog you want the focus to return to #txt. But in the case where a dialog is opened and you click somewhere else on the page, the editor will close and call the toolbar, including the dialog to close as well. If in this case the dialog would return focus to the editor, it would activate the editor again.

As far as I understand now, the event handling order is at least deterministic. It is not possible that some event gets a delay while others are processed earlier. This is what is meant by 'synchronous'. The exception is of course events like loading a file.

From the perspective of a program component, say the dialog, the situation can be quite unpredictable. It can bind a handler to the open event, and then call dialog("open"), but anything can happen between the call and the handler, if only because the editor has an event handler on the same event.

So my conclusion is 1) yes it is predictable but 2) it needs a sophisticated architecture to implement this.

In general the event model is synchronous and reentrant, meaning that if an event handler causes another event - the second event will be executed synchronously and only after completion will the first event continue executing.

This seems to be what you're trying to describe, in which case (B) is guaranteed.

Relevant source: http://www.w3.org/TR/DOM-Level-3-Events/#event-flow

Are there substantial differences in the way browsers implement the same-origin policy?

10 votes

I have a form on my homepage that is set up to submit via XHR POST to the URL https://mydomain.com/send_sms.

When I visit the non-SSL version of the homepage in Internet Explorer (http://mydomain.com) & submit the form, nothing happens. In Webkit console, I receive a helpful error stating Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin.

In Firefox 13 however, the request clearly submits & a returns a 200 OK, though the response body is blank. Furthermore, the server-side action (sending an SMS) is in fact triggered by the Firefox request but not the other browsers.

I always thought the same-origin policy denied even the sending of the request, but perhaps it's the browser receiving data from the response that's disallowed?

Anyone know if this is a purposeful difference in implementation (or possibly even an oversight) by Mozilla?

First of all, http://example.com and https://example.com are different origins. For XHR Level 1 this would mean, cross-origin requests are not allowed.

But for the current XHR (Level 2), which supports cross-origin requests when CORS is supported (by both server and client!), a cross-origin request can either be

For simple cross-origin requests, the browser is allowed to send the request. But when the response is received, it needs to check whether the server allows to share the resource. This is where the Access-Control-Allow-Origin header field and other Access-Control-* response header fields are checked. And only if this check is passed, the browser allows the script to read the response.

For other cross-origin requests, a preflight is required to negotiate with the server what information is allowed to be sent in the actual request. This preflight request is basically a OPTIONS request telling the server what the actual request will contain (request method and header fields). Then the server can decide whether it allows such request or not.

In your case, the observed behavior can have multiple reasons. I guess your send_sms script just doesn’t support the server side part for CORS.

Why is Number([]) === 0 and Number({}) === NaN in Javascript?

10 votes

I was looking at the first table on http://zero.milosz.ca/, and wanted to understand why, for example, 0 == [] and 0 != {}. I'm assuming it's because Number([]) == 0 and Number({}) == NaN. However, that part seems arbitrary. Why is an empty list 0 and empty object a NaN?

Using Number(some_object) will use the string representation of the given object. For your examples the string representations are:

js> ({}).toString();
[object Object]
js> [].toString();

js>

The string '[object Object]' cannot be converted to a number but the empty string '' can.

Can you have a javascript hook trigger after a DOM element's style object changes?

9 votes

An element has a javascript style object which contains the different names and values of css styles. I'd like to trigger a function every time this object changes without use of polling. Is there any way to do this in a way that is cross-browser compatible and would work reliably with third party code (because let's say you're providing a drop-in script)? Binding a javascript event like DOMAttrModified or DOMSubtreeModified won't suffice because they don't work in Chrome.

Edit 2:

  1. Fix for propertName in IE7 & IE8

Edit 1:

  1. Handle multiple elements
  2. Ordered the conditions as MutationObserver, DOMAttrModified and onpropertychange for better implementation.
  3. Added modified Attribute Name to the callback.

Thanks to @benvie for his feedback.

DEMO: http://jsfiddle.net/zFVyv/10/ (Tested in FF 12, Chrome 19 and IE 7.)

$(function() {
    (function($) {
        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

        function isDOMAttrModifiedSupported() {
            var p = document.createElement('p');
            var flag = false;

            if (p.addEventListener) p.addEventListener('DOMAttrModified', function() {
                flag = true
            }, false);
            else if (p.attachEvent) p.attachEvent('onDOMAttrModified', function() {
                flag = true
            });
            else return false;

            p.setAttribute('id', 'target');

            return flag;
        }

        $.fn.attrchange = function(callback) {
            if (MutationObserver) {
                var options = {
                    subtree: false,
                    attributes: true
                };

                var observer = new MutationObserver(function(mutations) {
                    mutations.forEach(function(e) {
                        callback.call(e.target, e.attributeName);
                    });
                });

                return this.each(function() {
                    observer.observe(this, options);
                });

            } else if (isDOMAttrModifiedSupported()) {
                return this.on('DOMAttrModified', function(e) {
                    callback.call(this, e.attrName);
                });
            } else if ('onpropertychange' in document.body) {
                return this.on('propertychange', function(e) {
                    callback.call(this, window.event.propertyName);
                });
            }
        }
    })(jQuery);

    $('.test').attrchange(function(attrName) {
        alert('Attribute: ' + attrName + ' modified ');
    }).css('height', 100);

});

Ref:

  1. Detect if DOMAttrModified supported
  2. DOMAttrModified for chrome
  3. Mutation Observer
  4. Why should we avoid using Mutation events?
  5. onPropertyChange IE

Mutation Observers is the proposed replacement for mutation events in DOM4. They are expected to be included in Firefox 14 and Chrome 18

Browser Support:

onpropertychange - is supported in IE (tested in IE 7)

DOMAttrModified - is supported in IE 9, FF and Opera

MutationObservers - is very new and it worked fine in Chrome 18. Not sure how far it is supported and yet to be tested in Safari.

Thanks @benvie on adding info about WebkitMutationObserver

I need a new way to detect if there has been a change to an elements HTML

9 votes

Right now im trying to find a way to detect when an elements HTML has changed.

I'm currently trying:

var a, b;
setInterval(function() {
    a = $('#chat').text();
}, 150);
setInterval(function() {
    b = $('#chat').text();
    if (a !== b) {
        alert("There has been a new message.");
    }
}, 200);​

What I do is every 150 milliseconds I check for the HTML of #chat and then every 200 seconds I check the HTML again and then check if variable a does not equal to variable b them in the future I will so something with that but for right now I just alert something.

You can see it live here: http://jsfiddle.net/MT47W/

Obviously this way is not working and is not very accurate at all. Is there a better/different to do/achieve this?

Thanks for any help, I've been trying to figure out how to do this a better for about a week now but I just can't find a fix for this and i'm hoping I posted this problem at the right place, and at the right time.

Use a var to store the element's current text then check against it in a setInverval and update the var to store the current text after checking:

var a = $('#chat').text();
setInterval(function() {
    if (a !== $('#chat').text()) { //checks the stored text against the current
        alert("There has been a new message."); //do your stuff
    }
    a = $('#chat').text(); //updates the global var to store the current text
}, 150); //define your interval time, every 0.15 seconds in this case

Fiddle

You may as well store the value in the .data() of the element to avoid using globals.

Example using .data():

$('#chat').data('curr_text', $('#chat').text());
setInterval(function() {
    if ($('#chat').data('curr_text') !== $('#chat').text()) {
        alert("There has been a new message.");
    }
     $('#chat').data('curr_text', $('#chat').text());
}, 150);

Fiddle

Another approach, to save client's memory, you can just store the number of child divs your #chat element has:

$('#chat').data('n_msgs', $('#chat').children().length);
setInterval(function() {
    if ($('#chat').data('n_msgs') !== $('#chat').children().length) {
        alert("There has been a new message.");
    }
     $('#chat').data('n_msgs', $('#chat').children().length);
}, 150);

Fiddle


EDIT: Here's my very final addition, with a DOM mutation event listener:

$('#chat').on('DOMNodeInserted', function() {
    alert("There has been a new message.");
});

Fiddle (not tested in IE < 8)

Note: As noted in the comments, even though mutation events are still supported they're classed as deprecated by W3C due to the performance loss and some incompatibilities across different browsers, therefore it's suggested to use one of the solutions above and only use DOM Mutation events when there's no other way around.

Mouseover event doesn't granulate on IE9 for sub elements, event doesn't start on IE8

9 votes

We were adapting a method posted here highlight a DOM element on mouse over, like inspect does to NOT use jQuery.

We came up with this solution so far: http://jsfiddle.net/pentium10/Q7ZQV/3/

This seams to work on Chrome and Firefox, but doesn't work as expected on IE.

  1. On IE9 for example the highlight doesn't occur on minor elements like the tag line eg: javascript, html, dom or the top line like: chat, meta, faq

    When I mouse over the javascript tag the big div is highligthed and this is wrong and it should be like we see in Firefox

  2. On IE8 and 7 it doesn't start, so that is another problem we need to fix

It turns out that in IE, elements that have no background (i.e. background: transparent) and the Gradient filter set do not receive mouse events. Demo

This is a happy coincidence, since you're using a RGBa background colour for your overlay and one of the workarounds for RGBa colours in IE is the Gradient filter.

By setting these styles on the overlay (for IE):

background: transparent;
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#7F000000,endColorstr=#7F000000)"; /* IE8 */
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#7F000000,endColorstr=#7F000000);   /* IE6 & 7 */
zoom: 1;

mouse events pass through the overlay and onto the underlying elements, so inner / minor elements are highlighted correctly.

Other issues that are present in IE7/8:

  • When using element.attachEvent, the event name needs to be prefixed with "on":

    document.body.attachEvent('onmouseover', function(e) { ... })
    
  • To find the target of the event, you need to access event.srcElement instead of event.target.

  • As rodneyrehm mentioned, Array.indexOf isn't supported.

So here's a version of your solution that also works in IE 7-9: http://jsfiddle.net/jefferyto/Q7ZQV/7/

(BTW The highlighting is wrong for inline elements that span more than one line, e.g. the "ask your own question" link in the "Browse other questions..." line.)

Match all combinations of any classes in jQuery

9 votes

I have two comma-separated selectors;

.class, .foo, .bar

.lorem, .ipsum, .potato

I'd like to be able to select any possible combination between these two groups. So it would select elements matching

.class.lorem
.class.ipsum
.class.potato
.foo.lorem
.foo.ipsum
.foo.potato
.bar.lorem
.bar.ipsum
.bar.potato

How can I achieve this effectively?

Select all elements with any class from the first set, and then filter out the elements which don't have a class from the other set:

$('.class, .foo, .bar').filter('.lorem, .ipsum, .potato')

Jquery | Get div elements in defined area

9 votes

is there a simple way to get the div elements fitting completely in a defined area?

Example:

http://i.imgur.com/oIw6i.png

<div id="redbox"> RESIZE DIV </div>

<div id="grid">
  <div id="box1"></div>
  <div id="box2"></div>
  <div id="box3"></div>
  <div id="box4"></div>
</div>

I got 4 Boxes (grey) and I am able to resize a div (red on top of all boxes). After resize I want to know which of the div elements are fitting completely in this area.

Does anyone knows how to do this? Is there a method or function in JQUERY?

It looks to me like the withinBox plugin might help you solve this (jquery.fn.withinBox). You could use the code like this:

var area = $('#redbox'),
    offset = area.offset(),
    selected = $('#grid div').withinBox(offset.left,
                                        offset.top,
                                        area.width(),
                                        area.height()
                                        );

What is the cleanest way to disable css transition effects temporarily?

8 votes

I have a DOM element with some/all of the following effects applied:

#elem {
  -webkit-transition: height 0.4s ease;
  -moz-transition: height 0.4s ease;
  -o-transition: height 0.4s ease;
  -ms-transition: height 0.4s ease;
  transition: height 0.4s ease;
}

I am writing a jQuery plugin that is resizing this element, I need to disable these effects temporarily so I can resize it smoothly.

What is the most elegant way of disabling these effects temporarily (and then re-enabling them), given they may be applied from parents or may not be applied at all.

Add an additional CSS class that blocks the transition, and then remove it to return to the previous state. This make both CSS and JQuery code short, simple and well understandable.

CSS:

.notransition {
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -o-transition: none !important;
  -ms-transition: none !important;
  transition: none !important;
}

!important was added to be sure that this rule will have more "weight", because ID is normally more specific than class.

JQuery:

$('#elem').addClass('notransition'); // to remove transition
$('#elem').removeClass('notransition'); // to return to previouse transition