Best jquery questions in April 2012

Return "True" on Empty jQuery Selector Array?

14 votes

I'm working on creating a more semantic way of checking for elements with jQuery. Using $("#element").length > 0 just doesn't really feel very well worded to me, so I'm making my own selector addition for use in .is:

if($("#element").is(":present")) {
  console.log("It's aliiiveeee!!");
}

That part was easy, like this:

$.extend($.expr[':'],{
    present: function(a) {
        return $(a).length > 0;
    }
});

I want to go a step further, and make it easy to see if an element doesn't exist, using similar syntax:

$.extend($.expr[':'],{
    present: function(a) {
        return $(a).length > 0;
    },
    absent: function(a) {
        return $(a).length === 0;
    }
});

$(function() {
  if($("#element").is(":absent")) {
    console.log("He's dead, Jim.");
  }
});

But this part is surprisingly hard to do. I think it's because I'm paring down the returned elements to get a result, and paring the selector to .length === 0 is the same as asking for no elelements: it returns false no matter what.

I've tried a lot of different ways to reverse things and get this to return true when the element doesn't exist, and false if it does:

return $(a).length === 0;

return !($(a).length > 0);

if(!($(a).length > 0)) { 
  return true;
} 

if($(a).length > 0) { 
  return false;
} else {
  return true;
}

return !!($(a).length === 0);

// etc...

Is there an easy way to get this to just return true if the element doesn't exist, and false if it does?

The definition of is:

Check the current matched set of elements against a selector, element, or jQuery object and return true if at least one of these elements matches the given arguments.

The problem is that since you have no elements, it's not possible that one of your elements matches some condition. jQuery is not even calling your code because there are no elements.

EDIT: To clarify slightly, your code is being called once for every element in your object (at least until one returns true). No elements means the code is never called. a in your code is always a single element.

EDIT2: With that in mind, this would be a more efficient implementation of present:

$.extend($.expr[':'],{
    present: function(a) {
        return true;
    }
});

Jquery UI autocomplete combobox button click event

11 votes

I'm experiencing weird behavior with jquery ui autocomplete when using it to create a combobox. Whenever I click on the scrollbar to scroll through the list of results AND then click on my combobox button to close the results the results list closes and then opens again. I expect it to close the menu.

Steps to Repro

  1. open jsfiddle demo
  2. Type 'i' in the autocomplete OR hit the dropdown button.
  3. Click on the vertical scroll to scroll the results
  4. Click on the dropdown button

Script to Create Button

 this.button = $("<button type='button'>&nbsp;</button>")
    .attr({ "tabIndex": -1, "title": "Show all items" })
    .insertAfter(input)
    .button({
         icons: {
             primary: "ui-icon-triangle-1-s"
         },
         text: false
    })
    .removeClass("ui-corner-all")
    .addClass("ui-corner-right ui-button-icon")
    .click(function () {

        // when i put breakpoint here, and my focus is not on input, 
        // then this if steatment is false????

        if (input.autocomplete("widget").is(":visible")) {
            input.autocomplete("close");
            return;
        }

        // work around a bug (likely same cause as #5265)
        $(this).blur();

        // pass empty string as value to search for, displaying all results
        input.autocomplete("search", "");
        input.focus();
});

CSS (force long results menu to scroll)

.ui-autocomplete {
    max-height: 100px;
    overflow-y: auto;
    /* prevent horizontal scrollbar */
    overflow-x: hidden;
    /* add padding to account for vertical scrollbar */
    padding-right: 20px;
}
/* IE 6 doesn't support max-height
 * we use height instead, but this forces the menu to always be this tall
 */
* html .ui-autocomplete {
    height: 100px;
}

My solution could be closing the widget even if focus is transferred to widget itself and not the input element?

Any ideas how to modify this code so it behaves this way?

Based on issues with the various click and mouse events for the automplete widget, I came up with this: jsFiddle example.

jQuery:

var input = $('#txtComplete');

var data = [];
var isOpen = false;

function _init() {
    for (var idx = 0; idx <= 100; idx++) {
        data.push('item: ' + idx);
    };
    input.autocomplete({
        source: data,
        minLength: 0,
        open: function(event, ui) {
            isOpen = true;
        },
        select: function(event, ui) {
            isOpen = false;
        }
    });
}

function afterInit() {
    var button = $("<button type='button'>&nbsp;</button>").attr("tabIndex", -1).attr("title", "Show all items").insertAfter(input).button({
        icons: {
            primary: "ui-icon-triangle-1-s"
        },
        text: false
    }).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon").click(function(event) {
        input.focus();
        if (isOpen) {
            input.autocomplete("close");
            isOpen = false;
        } else {
            input.autocomplete("search", "");
            event.stopImmediatePropagation();
        }
    });
}
$(window).click(function() {
    input.autocomplete("close");
    isOpen = false;
});
$(function() {
    _init();
    afterInit();
});​

What kind of object shows up in the console as [object Text]?

9 votes

Say I have the following element:

<p id="thingy">Here is some <em>emphasized</em> text!</p>

In a Javascript console, I'll get its contents with jQuery:

> var theContents = $('<p id="thingy">Here is some <em>emphasized</em> text!</p>').contents();

theContents is now an array that looks like this:

> theContents
["Here is some ", <em>​emphasized​</em>​, " text!"]

So far so good; it seems to be an array, where elements 0 and 2 are strings, and element 1 is a jQuery object. If I output just the first element, it seems to confirm my guess:

> theContents[0]
"Here is some "

However, if I try to concatenate it with another string, I see that I am lacking some understanding:

> 'Hello! ' + contents[0];
"Hello! [object Text]"

So that variable looks like a string, but it is in fact some kind of object. For that matter, the jQuery object in the middle doesn't show up as a regular object, either; it shows up as the raw markup.

Another question references the same problem, but doesn't actually explain it. I've found that I can use contents[0].textContent to solve my real problem, but that still doesn't help me understand exactly what is going on here. Can someone explain to me in detail why all this is behaving the way it is?

Most jQuery functions return a jQuery object, which for convenience looks and works like an array for most purposes. To quote the documentation, "A jQuery object contains a collection of Document Object Model (DOM) elements" (or "nodes"). So you can assume that each member of the collection is a DOM node, not a string, and accordingly the object you're looking at is a Text node.

In JavaScript when you do string concatenation each operand that isn't a string is automatically converted to one by calling its toString() method. So, just as "1,2,3" is the string representation of the array [1, 2, 3] and "[object HTMLDivElement]" represents a node created with the HTML "<div>", "[object Text]" represents a Text node.

You can read the specification here. Since interface Text inherits from CharacterData it has a data property that contains the string itself. And so:

var theContents = $( '<p id="thingy">Here is some <em>emphasized</em> text!</p>' )
                    .contents();

console.log( theContents[0].data );
// => "Here is some "

console.log( "Hello! " + theContents[0].data );
// => "Hello! Here is some "

Removing red eye from an Image on the client side using Jquery

9 votes

I have the following html code rendered on my client's browser:

<div id="Div">
  <img src="myImage.jpg" id="myImage"/>
</div>

This particular image is uploaded by the user and then displayed here. I need to allow my user to remove any red-eye from this image. I would like to do it without any postback ( I'm using CodeIgniter at the back ). Are there any available libraries for this in JQuery (or plain Javascript) ? If not what could be a good approach ?

There is a lot of things that go on in red eye removal

A. Eye Detection

B. Red Eye Region Mapping

C. Fill Color

D. Fuzz

E. Opaque

My advice

If not a JOB for Jquery and even PHP would not remove red eye effectively

Likely Solution

  1. Get a Jquery area selection script where users can select their red eyes them self ( With this you would be able to get the region (X1 , Y1 , X2 , Y2 , Height , Width ) example http://odyniec.net/projects/imgareaselect/

  2. Have a simple Color Picker where they can select replacement color ??? Default can be black

  3. Send request to imagemagick using exec in PHP for the red eye removal

  4. You can not output your image ...

EDIT 1

I was able to help you get a ready command line tool for this JOB

http://www.fmwconcepts.com/imagemagick/index.php http://www.fmwconcepts.com/imagemagick/redeye/index.php

Basic Concept

A. Create a desaturate copy of the input image

B. Perform a fuzzy floodfill to create a mask image

C. Composite the original with the desaturated image using the mask image

D. Apply a morphologic close operation to fill in the specular hole in the mask and then create a difference operation to create a new mask of just the hole

E. Apply the new mask to composite the previous result with a full lightness, zero saturation version of the original image

Sample Process

convert -quiet -regard-warnings "$infile" +repage "$tmpA1"
convert $tmpA1 -modulate $light,$sat,100 $tmpA2
proc=""
for ((i=0; i<np; i++)); do
proc="$proc matte ${pairArray[i]} floodfill"
done
convert $tmpA5 -fuzz $fuzz% -fill none -draw "$proc" \
-fill "rgba(255,255,255,1)" +opaque "rgba(0,0,0,0)" \
-fill "rgba(0,0,0,1)" -opaque "rgba(0,0,0,0)" \
-alpha off -negate $tmpA3
if [ "$dilate" = 0 ]; then
dilation=""
else
dilation="-morphology dilate disk:$dilate"
fi
convert $tmpA1 $tmpA2 $tmpA3 -compose over -composite $tmpA2
convert $tmpA3 \( +clone -morphology close disk:$rad $dilation \) \
-compose difference -composite -auto-level \
-negate -threshold 0 -negate $tmpA4
convert $tmpA2 \( $tmpA1 -modulate 100,0,100 \) $tmpA4 \
-compose over -composite $outfile

I hope this helps

Thanks

:)

Avoiding .call() and .apply() using .bind()

9 votes

I'm looking for a way to accomplish a certain task and that is, going from

jQuery.when.apply( null, promiseArray ).done(...)

to

when( promiseArray ).done(...)

As you might know, .bind() can get used to create something like default arguments and also doing some quite nifty stuff. For instance, instead of always calling

var toStr = Object.prototype.toString;
// ...
toStr.call([]) // [object Array]

we can do it like

var toStr = Function.prototype.call.bind( Object.prototype.toString );
toStr([]) // [object Array]

This is fairly cool (even if there is a performance penality invoking .bind() like this, I know it and I'm aware of it), but I can't really accomplish it for jQuerys .when call. If you got an unknown amount of promise objects, you usually push those into an array, to then be able to pass those into .when like in my first code snippet above.

I'm doing this so far:

var when = Function.prototype.apply.bind( $.when );

Now we can go like

when( null, promiseArray ).done(...)

This works, but I also want to get rid of the need to pass in null explicitly every time. So I tried

var when = Function.prototype.apply.bind( $.when.call.bind( null ) );

but that throws at me:

"TypeError: Function.prototype.apply called on incompatible null"

I guess I'm sitting over this for too long now and can't think straight anymore. It feels like there is an easy solution. I don't want to use any additional function to solve this issue, I'd absolutely prefere a solution using .bind().

See a complete example here: http://jsfiddle.net/pp26L/

This should work:

when = Function.prototype.apply.bind( $.when, null);

You just bind (or curry, if you prefer) the first argument of .bind and fix it to null.

Fiddle.

CSS circles without width or height? : Is this possible with pure CSS or not?

8 votes

I can turn a div into a circle like this:

.circle {
 background-color: rgba(0, 0139, 0139, 0.5);
 height: 200px;
 width: 200px;
 -moz-border-radius:50%;
 -webkit-border-radius: 50%;
 border-radius:50%;
}

<div class="circle"></div>
</div>

But i have to specify width height:

I want to display three rows of text in DIV's with "no-wrap" so each of the 3 segments of text have there own line and are not wrapped.

I want to display these in the center of a circle and have the circle expand to fit the lines of text.

The text lines will be pulled from a database via PHP, and will vary in character length.

The problem is the method shown above only works if the width / height is specified.

Is this possible with CSS using only, using percentages or would i need a JS work around.

thanks in advance.

Pure CSS Solution with some caveats

This fiddle demonstrates a solution using only css. It works flawlessly (I think) in modern browsers (IE9+, which is needed for border-radius anyway) with single lines of text. Caveats are:

  1. As you can see by the pink "circle" the text must all be contained in a single element (not multiple spans as in the pink). That is not a big problem.
  2. To get any kind of "padding" one needs to put a transparent border on the span set to the "padding" size. This should also not normally be a big issue, since it is unlikely you would want borders inside the circle.
  3. As you can see by the css on the cyan circle, if multiple lines of text are expected (or forced in my case by a max-width), then css for margin-top and top properties must be set according to the number of text lines. This could be an issue depending on application. On the stacked version, IE9 needed overflow: auto set to get it to size correctly.
  4. As you can see by the red circle if you narrow the display area, if white-space: nowrap is not set and a circle begins wrapping its single line of text, then some ovular distortion of the circle occurs.

Each web designer would have to determine if the limitations of this solution can be accounted for or not. If not, then the javascript solution posted here by rgthree should work well. But if only a single line (or some set number of lines, like in my cyan circle) are expected, then this css solution should work well.

Why does jQuery not provide a .firstChild method?

8 votes

I have seen plenty of discussion regarding the fastest way to select a first child element using jQuery. As can be expected, the native DOM firstChild property is much faster than using a jQuery selector or combination of selectors -- see http://jsperf.com/jquery-first-child-selection-performance/6. This is not usually a problem -- either it's being used in a place where performance is not a big deal, or it's easy enough to just access the DOM element and use its .firstChild property. However, there are a couple problems with this:

  • firstChild could return a text or comment node, rather than an element, as a jQuery selector would return
  • If I need to select the first child of multiple elements, I must either use a slow selector, or go to a lot of extra work iterating over DOM elements, adding them to a collection, then putting them back into a jQuery object.

It seems to me that the cost of adding a firstChild method to the core jQuery library would be far smaller than the benefits. I took my own shot at creating such a method for my own use:

$.fn.firstChild = function() {
    var ret = [];

    this.each(function(){
        var el = this.firstChild;

        //the DOM firstChild property could return a text node or comment instead of an element
        while (el && el.nodeType != 1)
            el = el.nextSibling;

            if (el) ret.push(el);
        });

        //maintain jQuery chaining and end() functionality
        return this.pushStack(ret);
    };
}

In the tests i created at http://jsperf.com/jquery-multiple-first-child-selection, this function performs more than five times faster than any other option. The tests are based on the tests mentioned above, but are selecting the first children of multiple elements, rather than a single element.

Is there something I am missing? A technique that I should be using? Or is this an issue than one should never worry about? Is there a reason to not include a function like this in jQuery?

"Why does jQuery not provide a .firstChild method?"

Feature creep, most likely.

It can be accomplished with other methods as you stated, and if performance is a concern, you can extend jQuery for that specific need as you've done.


You can improve performance in your code a little more...

$.fn.firstChild = function () {
    var ret = [];
    // use a for loop
    for (var i = 0, len = this.length; i < len; i++) {
        var this_el = this[i],
            el = this_el.firstElementChild; // try firstElementChild first
        if (!el) {
            el = this_el.firstChild;
            while (el && el.nodeType != 1)
                el = el.nextSibling;
        }
        if (el) ret.push(el);
    }
    //maintain jQuery chaining and end() functionality
    return this.pushStack(ret);
};

What are some common ways to cause memory leaks using JQuery/JavaScript?

8 votes

My question assumes you are creating a web page that will be displayed for a "long time." I'm curious as to what are some of the common gotchas that will cause memory leaks when using JQuery/JavaScript in such a scenario? For instance what happens in terms of memory when you call $.remove() on a collection of elements? Thanks!

JavaScript uses garbage collection to reclaim the memory occupied by strings, objects, arrays, and functions that are no longer in use. This frees you, the programmer, from having to explicitly deallocate memory yourself and is an important part of what makes JavaScript programming easier than, say, C programming.

References : Check this for more and an answer on SO.

Memory issues in event registering mechanism MDN

var i;  
var els = document.getElementsByTagName('*');  

// Case 1  
for(i=0 ; i<els.length ; i++){  
    els[i].addEventListener("click", function(e){/*do something*/}, false});  
}  

// Case 2  
function processEvent(e){  
    /*do something*/  
}  

for(i=0 ; i<els.length ; i++){  
  els[i].addEventListener("click", processEvent, false});  
}  

In the first case, a new (anonymous) function is created at each loop turn. In the second case, the same previously declared function is used as an event handler. This results in smaller memory consumption. Moreover, in the first case, since no reference to the anonymous functions is kept, it is not possible to call element.removeEventListener because we do not have a reference to the handler, while in the second case, it's possible to do

myElement.removeEventListener("click", processEvent, false)

How to detect the dragleave event in Firefox when dragging outside the window

7 votes

Firefox doesn't properly trigger the dragleave event when dragging outside of the window:

https://bugzilla.mozilla.org/show_bug.cgi?id=665704

https://bugzilla.mozilla.org/show_bug.cgi?id=656164

I'm trying to develop a workaround for this (which I know is possible because Gmail is doing it), but the only thing I can come up with seems really hackish.

One way of knowing when dragging outside the window has occurred it to wait for the dragover event to stop firing (because dragover fires constantly during a drag and drop operation). Here's how I'm doing that:

var timeout;

function dragleaveFunctionality() {
  // do stuff
}

function firefoxTimeoutHack() {
  clearTimeout(timeout);
  timeout = setTimeout(dragleaveFunctionality, 200);
}

$(document).on('dragover', firefoxTimeoutHack);

This code is essentially creating and clearing a timeout over and over again. The 200 millisecond timeout will not be reached unless the dragover event stops firing.

While this works, I don't like the idea of using a timeout for this purpose. It feels wrong. It also means there's a slight lag before the "dropzone" styling goes away.

The other idea I had was to detect when the mouse leaves the window, but the normal ways of doing that don't seem to work during drag and drop operations.

Does anyone out there have a better way of doing this?

UPDATE:

Here's a link to a demo illustrating the problem I'm seeing. The code is also pasted below: http://philipwalton.com/demos/drag-and-drop.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Drag and Drop Issue</title>
  <script src="http://code.jquery.com/jquery.js"></script>
</head>
<body>
  Open up the console and look at what number is reporting when dragging files in and out of the window. The number should always be 0 when leaving the window, but in Firefox it's not.
  <script type="text/javascript">
    $(function() {
      var counter = 0;
      $(document).on('dragenter', function(e) {
        counter += 1;
        console.log(counter, e.target);
      });
      $(document).on('dragleave', function(e) {
        counter -= 1;
        console.log(counter, e.target);
      });
    });
  </script>  
</body>
</html>

I've found a solution. The problem was not so much that the dragleave event wasn't firing; rather, the dragenter event was firing twice when first dragging a file into the window (and additionally sometimes when dragging over certain elements). My original solution was to use a counter to track when the final dragleave event was occuring, but the double firing of dragenter events was messing up the count. (Why couldn't I just listen for dragleave you ask? Well, because dragleave functions very similarly to mouseout in that it fires not only when leaving the element but also when entering a child element. Thus, when dragleave fires, your mouse may very well still be within the bounds of the original element.)

The solution I came up with was to keep track of which elements dragenter and dragleave had been triggered on. Since events propagate up to the document, listening for dragenter and dragleave on a particular element will capture not only events on that element but also events on its children.

So, I created a jQuery collection $() to keep track of what events were fired on what elements. I added the event.target to the collection whenever dragenter was fired, and I removed event.target from the collection whenever dragleave happened. The idea was that if the collection were empty it would mean I had actually left the original element because if I were entering a child element instead, at least one element (the child) would still be in the jQuery collection. jQuery also saved me tons of time because it automatically does duplicate checking, so event.target doesn't get added twice, even when Firefox was incorrectly double-invoking dragenter.

Phew, anyway, here's a basic version of the code I ended up using. I've put it into a simple jQuery plugin if anyone else is interested in using it. Basically, you call .draghover on any element, and draghoverstart is triggered when first dragging into the element, and draghoverend is triggered once the drag has actually left it.

// The plugin code
$.fn.draghover = function(options) {
  return this.each(function() {

    var collection = $(),
        self = $(this);

    self.on('dragenter', function(e) {
      if (collection.size() === 0) {
        self.trigger('draghoverstart');
      }
      collection = collection.add(e.target);
    });

    self.on('dragleave', function(e) {
      // timeout is needed because Firefox 3.6 fires the dragleave event on
      // the previous element before firing dragenter on the next one
      setTimeout( function() {
        collection = collection.not(e.target);
        if (collection.size() === 0) {
          self.trigger('draghoverend');
        }          
      }, 1);
    });
  });
};

// Now that we have a plugin, we can listen for the new events 
$(window).draghover().on({
  'draghoverstart': function() {
    console.log('A file has been dragged into the window.');
  },
  'draghoverend': function() {
    console.log('A file has been dragged out of window.');
  }
});

how to display lightbox after Video Play Finishes?

6 votes

I have a youtube video.

I want to show a lightbox when it stops playing. I need this to be done using javascript/jQuery or PHP. Ajax is also fine.

I looked for a solution but didn't find one that worked.

If you can use youtube api then, something like this should work:


<script type="text/javascript">
$(document).ready(function() {
var player;
    function onYouTubePlayerAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'YmHAAqOsBqA',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
    }
    function onPlayerReady(event) {
        event.target.playVideo();
    }
    function onPlayerStateChange(event) {        
        if(event.data === 0) {          
            //completed playing
            //open lightbox
            $('#yourElementId a').lightBox();
        }
    }
});
</script>

Did you mean something like this.

Hope it helps

how to make unchecked check box return a value with jQuery serialize?

6 votes

I have an HTML form with some checkboxes. I use jQuery .serialize() function to make a query string to submit to the database. The problem I am having is that when a checkbox is unchecked, the .serialize() function does not register it in the query string.

My problem is illustrated in this jsfiddle: http://jsfiddle.net/cTKhH/.

This is a problem because i still need to save a value of the unchecked check box to the database. Right now the information is only saved when the check box is checked. When it is unchecked, and the information from .serialize() is submitted, no change is made since there is no information submitted.

Does anyone know how to make my .serialize() function return the unchecked value for all check boxes when they are unchecked?

Thanks!!

** EDIT **

Just a little more info, I know now why the unchecked check box is not submitted, because it is not a "successful" form control, see here: http://www.w3.org/TR/html401/interact/forms.html#successful-controls.

Hopefully I still modify the .serialize() function to submit unchecked values.

http://jsfiddle.net/cTKhH/16/

jquery find exact string with no more or less

6 votes

I have some text from a breadcrumb which I am using to open menu items on a page. For example, say the bctext = 'pasta'.

I want to target the word "pasta", but not say "yadda yadda yadda pasta". Only an instance of the single word "pasta" should match, or if bctext were a phrase, then it would only find the exact phrase.

This is what I have so far:

$('ul#accordion a:contains(' + bctext + ')')

But this finds "yadda yadda pasta", of course.

I get the bctext with the following:

var bctext = $('#CategoryBreadcrumb ul li:last-child').prev().children().text();

Then, I edit the menu with the following:

$('ul#accordion a:contains(' + bctext + ')').parent()
                                            .addClass('special')
                                            .children('ul')
                                            .css('display','block'); 

Is what I'm going for possible?

$('ul#accordion a').filter(function() {
    return $(this).text() == bctext;
}).parent().addClass('special').children('ul').css('display','block');

:contains() is not a native selector anyway so using .filter() with a custom callback won't have any performance drawbacks.

Saving javascript objects using jquery and passing an ID from database

5 votes

I am using jQuery to save the values of my javascript objects. I need to retreive the ID of inserted object from the database. I know how to do it, if the Save function is within the javascript object (see code below). But how can I set the ID variable, if the Save function is not in the javascript object?

Working:

Person = function() {
    var self = this;

    self.ID;
    self.Name;
    self.SurName;

    self.Save = function() {
        $.ajax({
            type: "POST",
            url: "Save",
            contentType: "application/json; charset=utf-8", 
            data: JSON.stringify({ Name: self.Name, SurnName: self.SurName }),
            dataType: "json",
            success: function (result) {
                var ID = result.d.ID; //this is the ID retreived from database
                self.ID = ID; //set the ID, it works, since I can reference to self
            }
        });
    };
}¨

So how would I now implement a function (outside the Person class!) like:

SavePerson = function(p) {
     $.ajax({
        type: "POST",
        url: "Save",
        contentType: "application/json; charset=utf-8", 
        data: JSON.stringify({ Name: p.Name, SurnName: p.SurName }),
        dataType: "json",
        success: function (result) {
            var ID = result.d.ID; //this is the ID retreived from database
            p.ID = ID; //set the ID, it doesn't work, becouse if I call SavePerson repetedly for different objects, a p will not be a correct person.
        }
    });
};

Just to clarify, you would like the Person object id property to be updated with the recent save? If so the following script would suffice. I have used deferred's to ensure that p.ID is only updated upon completion of the asynchronous request.

$.Person = function() {
    var self = this;
    self.ID;
    self.Name;
    self.SurName;
}

$.SavePerson = function() {
var dfd = $.Deferred();
     $.ajax({
        type: "POST",
        url: "Save",
        contentType: "application/json; charset=utf-8", 
        data: JSON.stringify({ Name: p.Name, SurnName: p.SurName }),
        dataType: "json",
        success: dfd.resolve
    });
return dfd.promise();
};

var p = new $.Person();

$.SavePerson().then(function(result){
    p.ID = result.d.ID;
});

Alternative to jQuery when just requiring DOM traversal, $.ajax & Deferred

5 votes

For most JavaScript projects that I work on, I want a simple, light-weight UI stack.

Currently I use jQuery in my projects, however when I actually take a step back and look at the code, I'm only really using it for:

Is there another library (I don't want to handle all the various cross-browser & ES3/ES5 differences myself) that can provide me these features without all the additon stuff that I personally don't need?

Dojo springs to mind, but I have little experience with that so far, and would ideally like to hear from those who have used multiple libraries on this.

In minimized form, Dojo is 136kb, jQuery is 96kb. Moving to dojo is not going in the right direction.

The issues you should consider are:

  1. Suitability of library for your purpose
  2. Size of library
  3. Likelihood that it will be precached already
  4. Your familiarity with the functionality of the library
  5. Availability on a popular, public CDN
  6. Good support on the net and great documentation
  7. Good reputation for reliability, cross browser support and regular updates

Go through each of these and unless you find another library that scores well on these, jQuery may be your best bet. It is surprisingly compact for what it offers you and it doesn't really have a lot of stuff that isn't in your list of things you want. jQuery has done a pretty good job of keeping the core library focused on its central mission and let UI stuff go into jQueryUI and most everything else into their own plug-in libraries.

If you're obsessed about optimizing the code you include to only be the things you need, then you may want to look at YUI. It was designed to be modular so that you can specify only the modules you want and then you can prebuild a chunk of code that only has those modules in it (or you can dynamically load just the modules you want). My sense is that YUI is somewhat overdesigned in this regard and it's cumbersome to use for quick projects because you have to spend the time to figure out which modules you need and generate that build each time. Once you get a bunch of modules loaded, it's not that compact either which is where you find that jQuery is surprisingly compact for what it includes.

In general, you should not worry about the things that a library includes that you are not using. Just look at the overall size and suitability of the libraries that do meet your needs. You can probably find a library that does only what you want and is bigger than jQuery and isn't widely cached so that wouldn't be a win.

There are compact libraries out there for just ajax or just deferred, but you probably want one with ajax and deferred implemented together so you can use deferred with ajax (like jQuery has done). Libraries that do extensive DOM manipulation tend to be more than just that because they are more designed to be your core library and most people have other needs besides just DOM manipulation.

In the end, I'd suggest that you shouldn't care what your library has in it that you don't need. Just evaluate it's overall suitability vs. the alternatives.

My .on() is acting like .bind(), not .live()

5 votes

I have a complicated nested form (Ryan Bates' version) with .live() attached to some of the dynamically generated elements, which I'm now transitioning over to .on() along with an upgrade from Jquery 1.4 to 1.7.

Here's a sample of one of the ~22 changes:

# old version with .live()
$('.options .image').live('click', function(){
    console.log('clicked .options')
})

# new version with .on()
$('.options').on('click', '.image', function(){
    console.log('clicked .options')
})

The changes work perfectly well for the form elements that already exist but they are failing for any nested elements that are dynamically created afterwards. Hence, it's working more like Jquery's bind than live. Do you know what might be going on here?

Due to the exceeding complexity of the code and lots of partials I'm leaving it out for now (hoping you might have a hunch!). Thanks.

As per 3nigma's comment but modified with your original selector, this will work:

$(document).on('click', '.options .image', function() {
  console.log('clicked .options');
});

However, I don't think setting document as listener is usually the way to go. In your original version with .live() you are selecting .image nodes within the .options node.

But the question doesn't say which parts are loaded dynamically. I suspect that .options is also part of the content that's loaded dynamically. The first selector when using .on() for delegating listeners has to be something that is NOT destroyed:

$('#someWrapper').on('click', '.options .image', function() {
  console.log('clicked .options');
});

#someWrapper doesn't need to be a new wrapper element, it can be any ancestor (what some people call a "parent"... but that's a misnomer since it can be a grandparent or great-grandparent or whatever!) that is not destroyed. The closer to the target selector (.options .image) the better.

Multiple ajax calls at same time

5 votes

I have developed some websites and I always stumble a the same point: multiple ajax calls. I have a main page where all the content is loaded asynchronously. When the page is loaded, there are four INDEPENDENT calls that "draw" the page by areas (top, left, right and bottom) and while it are loaded I show to the user the typical ajax spins. So, when a request is received by the browser I execute the callback and the different areas are drawing at different time. The fact is that the answer for the server sometimes are mixed up, I mean, the answer of top is drawn in the left or vice-versa.

I've tried some solutions like creating a timestamp in each request to indicate to the browser and server that each request is different.

Also I've tried to configure some parameters of cache in the server, in case.

The only way in which works has been including the request2 in the callback of the one, etc.

Anyone knows the proper way to do it or ever has beaten this issue?? I don't want to do chained request.

Thanks

Here is an example of what I mean:

$(document).ready(function() {

$.get('/activity',Common.genSafeId(),function(data){$('#stream').html(data);$("#load_activity").addClass("empty");});
$.get('/messages',Common.genSafeId(),function(data){$('#message').html(data);$("#load_messages").addClass("empty");});
$.get('/deals',Common.genSafeId(),function(data){$('#new_deals_container').html(data);$("#load_deal").addClass("empty");});
$.get('/tasks',Common.genSafeId(),function(data){$('#task_frames').html(data);$("#load_task").addClass("empty");});});

And the html is a simple jsp with four container each one with a different id.

CLOSURES

Closures are a little mind-blowing at first. They are a feature of javaScript and several other modern computing languages.

A closure is formed by an executed instance of a function that has an inner function (typically an anonymous event handler or named method) that needs access to one or more outer variables (ie. variables that are within the outer function but outside the inner function). The mind-blowing thing is that the inner function retains access to the outer variables even though the outer function has completed and returned at the time that the inner function executes!

Moreover, variables trapped by a closure are accessible only to inner functions and not to the further-out environment that brought the closure into being. This feature allows us, for example, to create class-like structures with private as well as public members even in the absence of language keywords "Public" and "Private".

Closures are made possible by inner functions' use of outer variables suppressing javaScript's "garbage collection" which would otherwise destroy the outer function's environment at some indeterminate point after completion.

The importance of closures to good, tidy javaScript programming cannot be overstressed.

In the code below the function getData() forms, at each call, a closure trapping id1 and id2 (and url), which remain available to the anonymous ajax response handler ($.get's third argument).

$(document).ready(function() {

    function getData(url, id1, id2) {
        $.get(url, Common.genSafeId(), function(data) {
            $(id1).html(data);
            $(id2).addClass("empty");
        });
    }

    getData('/activity', '#stream', '#load_activity');
    getData('/messages', '#message', '#load_messages');
    getData('/deals', '#new_deals_container', '#load_deal');
    getData('/tasks', '#task_frames', '#load_task');

});

Thus, rather than writing four separate handlers, we exploit the language's ability to form closures and call the same function, getData(), four times. At each call, getData() forms a new closure which allows $.get's response handler (which is called asynchronously when the server responds) to address its DOM elements.

Editing and Saving user HTML with Javascript - how safe is it?

5 votes

For example I have a Javascript-powered form creation tool. You use links to add html blocks of elements (like input fields) and TinyMCE to edit the text. These are saved via an autosave function that does an AJAX call in the background on specific events.

The save function being called does the database protection, but I'm wondering if a user can manipulate the DOM to add anything he wants(like custom HTML, or an unwanted script).

How safe is this, if at all?

First thing that comes to mind is that I should probably search for, and remove any inline javascript from the received html code.

Using PHP, JQuery, Ajax.

Not safe at all. You can never trust the client. It's easy even for a novice to modify DOM on the client side (just install Firebug for Firefox, for example).

While it's fine to accept HTML from the client, make sure you validate and sanitize it properly with PHP on the server side.

Does RegisterStartupScript increase page size

4 votes

I'm using this code in a page:

<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:Timer ID="timer" Interval="4000" runat="server" OnTick="timer_Tick" />

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <asp:Panel ID="pnlAlarm" runat="server" CssClass="pnlAlarm" ClientIDMode="Static">
            <div id="Alarm">
                <asp:Label ID="lblContent" runat="server" Text="Updating" CssClass="AlarmLogo"></asp:Label>
                    ClientIDMode="Static" />
            </div>
        </asp:Panel>
    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="timer" />
    </Triggers>
</asp:UpdatePanel>

and in code behind I use this simple code:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        Session["nima"] = 1;
    }
}
protected void timer_Tick(object sender, EventArgs e)
{
    int i = int.Parse(Session["nima"].ToString());
    if (i==3)
    {
        lblContent.Text = i.ToString();
        ScriptManager.RegisterStartupScript(this, GetType(), "AlarmMessage", "$('#pnlAlarm').slideToggle();", true);
        Session["nima"] = 0;
    }
    else
    {
        i = i + 1;
        Session["nima"] = i;
    }
}

I want to know every time that I use RegisterStartupScript , $('#pnlAlarm').slideToggle(); add to my page and increase my page size?

thanlks

By definition, that method will:

register a startup script block that is included every time that an asynchronous postback occurs.

So yes, it will be included, and therefore increase your page size.

msdn ScriptManager.RegisterStartupScript Method

jQuery GET html as traversable jQuery object

4 votes

This is a super simple question that I just can't seem to find a good answer too.

$.get('/myurl.html', function(response){
     console.log(response); //works!
     console.log( $(response).find('#element').text() ); //null :(
}, 'html');

I am just trying to traverse my the html response. So far the only thing I can think of that would works is to regex to inside the body tags, and use that as a string to create my traversable jQuery object. But that just seems stupid. Anyone care to point out the right way to do this?

Maybe its my html?

<html> 
    <head> 
       <title>Center</title> 
    </head> 
    <body> 
        <!-- tons-o-stuff -->
    </body>
</html>

This also works fine but will not suit my needs:

$('#myelem').load('/myurl.html #element');

It fails because it doesn't like <html> and <body>.

Using the method described here: A JavaScript parser for DOM

$.get('/myurl.html', function(response){
     var doc = document.createElement('html');
     doc.innerHTML = response;

     console.log( $("#element", doc).text() );
}, 'html');

I think the above should work.

jquery .get data manipulation

4 votes

I am using below code to get a page:

$.get('http://example.com/page1.html', function (data) {

});

Now lets imagine there is a #content div inside that page1.html and I need to read it's inner html as I already have #content div on page where Ajax call is occurring.

What is the right way to do this? I've tried with:

data = $(data).find('#content').html();
$("#content").empty().append(data);

But it seems that html() function is not the right one as it returns null, while contents() is returning data but I am not skillful enough to get only what I need from it.

Any help appreciated, thanks!!

Untested:

var content = $("#content", data).html(); // or var content = $("#content", $(data)).html();

$("#content").html(content);

EDIT: How about this?

$('#content').load("http://example.com/page1.html #content");

From: http://api.jquery.com/load/ - "loading page fragments".