JQuery

Javascript – jQuery – Stopping Event Propagation – stopImmediatePropagation

0

Recently ran into another issue where I had two separate and de-coupled event handlers tied to the same dom element, specifically a form submit. However, the first event handler returned false if certain checkboxes were not checked (business rules), but the false was ignored by the second event handler, and still executed. After some searching I came across the jQuery stopImmediatePropagation function, which gave teeth back to the return false, by not executing any subsequent event handlers, and solved my issue.

Example:

$('#formId').submit(function(e) {

    var j=0;
    
    for(j; j<this.length; j++) {
        if (this[j].type === 'checkbox' && this[j].checked) {
            somethingSelected = true;
        }
    }

    if (!somethingSelected) {

        alert('Must select something to continue');
                
        e.stopImmediatePropagation();

        return false;
    }
            
    return true;
});

$('#formId').submit(function(e) {

    // If the previous event handler returned false, this event handler will not be executed
});

Javascript – jQuery – Property Submit of Object htmlformelement is not a Function

0

Recently ran into an issue while trying to add some jQuery logic to a form element, where the following error was being generated in the Javascript console every time I submitted the form: Uncaught TypeError: Property ‘submit’ of object # is not a function.

After some research, it was noted that there must be some other DOM element with the name or id of ‘submit’. So I viewed source and sure enough, found that the previous dev added the ‘name=”submit”‘ attribute to the “input” tag. After I changed the attribute to ‘name=”formButton”‘, everything worked as expected.

Javascript – JQuery – Google Analytics – Submit Form Using GET Instead of POST

0

Was working on adding Google Analytics cross domain tracking for a form which uses the GET (instead of POST) method. The problem I was running into was the Google Analytics Tracking Cookie (GATC) data was not being added to the url, because the form’s data was overriding Google’s data. And I couldn’t switch the GET to a POST due to some low level and multiple redirect issues which occurred within the actions script. So I did some Googling around and came across some code snippets which I ended up implementing for my final solution, and wanted to share with you, in case you run into the same issue.

$(document).ready(function() {
    $('#formId').submit(function(e) {

        try {

            e.preventDefault();

            var form = this;

            if (typeof _gat !== 'undefined') {

                _gaq.push(['_linkByPost', this]);

                var pageTracker = _gat._getTrackerByName();

                var url = pageTracker._getLinkerUrl(form.action);

                var match = url.match(/[^=&?]+\s*=\s*[^&#]*/g);

                for ( var i = match.length; i--; ) {

                    var spl = match[i].split("=");

                    var name = spl[0].replace("[]", "");

                    var value = spl[1];

                    $('<input>').attr({
                        type: 'hidden',
                        name: name,
                        value: value
                    }).appendTo(form);
                }
            }

            setTimeout(function() { form.submit(); }, 400);
        } catch (e) { form.submit(); }
    });
});

Notice, that with the above snippet we can localize the GATC values that Google was going to append to the URL via POST, then convert them into hidden fields, linked to the form being submitted. So when the form is submitted the hidden values, along with the form’s organic values will all now be part of the URL and available to the form action.

Symfony – Add ReCaptcha to JQuery Dialog (Lightbox)

5

The following solution of adding ReCaptcha to a JQuery Dialog (Lightbox) makes use of the sfFormExtraPlugin, not the sfReCaptchaPlugin. The reason is because the following solution was developed in Symfony 1.2+, and we had access to the Symfony form architecture.

Out of the box, the sfFormExtraPlugin sfWidgetFormReCaptcha::render() will not work in lightboxes because it results in a document.write(). Consider the following:

// sfWidgetFormReCaptcha::render() produces the following javascript
<script type="text/javascript" src="http://api.recaptcha.net/challenge?k=6Let7r0SAAAAAJFp77tW4gRze7r5y89Cql_msPcm"></script>

// Which produces the following javascript
var RecaptchaState = {
    site : '6Let7r0SAAAAAJFp77tW4gRze7r5y89Cql_msPcm',
    challenge : '03AHJ_VusnO7jeI3VF-cHgOIv9RY9RIpYl2QWea_LULIdL8xrM9PZdcZZ7I9gFf4gSbr1fxGCSQjQZPJQ1sa6p1oEI9U_nkU8f2SjczxjH6nzmy43Q-m_8rnxWhhRUIDa7iTPEwo4-dwi-FipyMHsSAz-nE5yfFQfZog',
    is_incorrect : false,
    programming_error : '',
    error_message : '',
    server : 'http://www.google.com/recaptcha/api/',
    timeout : 18000
};

document.write('<scr'+'ipt type="text/javascript" s'+'rc="' + RecaptchaState.server + 'js/recaptcha.js"></scr'+'ipt>');</pre>

Note the resulting document.write() code produced by recaptcha.

Recaptha offers multiple ways to access their api, so instead of the solution implemented by the devs of the sfWidgetFormReCaptcha plugin, I opted to introduce custom code which will produce the same result, except it will be lightbox friendly.  As with any Symfony plugin, I made sure not to overwrite core logic so it doesn’t increase technical debt with respect to future plugin upgrades etc. (unless the core logic changes such that the custom code must follow suit).

First, we need to override the default plugin code so we can add our custom code, and thanks to Symfony autoloading, the following changes should work out of the box. Also note, the myWidgetFormCaptcha class name follows symfony naming conventions to indicate Symfony core code vs custom code.

We need to create a new file which will extend sfWidgetFormReCaptcha;

mkdir -p /path/to/symfony_code/lib/form/myExtraFormPlugin/lib/widget
touch /path/to/symfony_code/lib/form/myExtraFormPlugin/lib/widget/myWidgetFormReCaptcha.class.php #lol @ touch myWidget

You can use whichever path you wish, just make sure it’s in the /path/to/symfony_code/lib dir so it will be included when Symfony autoloads files. I chose the above path to maximize flexibility if I ever need to override any other sfFormExtraPlugin widgets.

Now that we have our override class file in place, lets add the code:

<?php
// /path/to/symfony_code/lib/form/myExtraFormPlugin/lib/widget/myWidgetFormReCaptcha.class.php

/**
 * Extending plugin functionality, see parent class for full docs
 */
class myWidgetFormReCaptcha extends sfWidgetFormReCaptcha
{
 /**
 * @see sfWidgetForm
 */
public function render($name, $value = null, $attributes = array(), $errors = array())
{
    $server    = $this->getServerUrl();
    $key    = $this->getOption('public_key');

    if ((array_key_exists('context', $attributes)) &&
        ($attributes['context'] == 'lightbox')) {

        // Arbitrary flag, unset it
        unset($attributes['context']);

        return javascript_tag("
            Recaptcha.create('".$key."', 'captchaWrap', {custom_translations: {instructions_visual:'" . __('recaptcha_instructions_visual') . "',instructions_audio:'" . __('recaptcha_instructions_audio') . "',play_again:'" . __('recaptcha_play_again') . "', cant_hear_this:'" . __('recaptcha_cant_hear_this') . "', visual_challenge:'" . __('recaptcha_visual_challenge') . "', audio_challenge:'" . __('recaptcha_audio_challenge') . "', refresh_btn:'" . __('recaptcha_refresh_btn') . "', help_btn:'" . __('recaptcha_help_btn') . "', incorrect_try_again:'" . __('recaptcha_incorrect_try_again') . "'}, theme:'". sfConfig::get('recaptchaTheme', sfConfig::get('clientid'), 'text', 'clean') ."', lang:'en'});
        ") . '<div id="captchaWrap"></div>';
    }

    parent::render($name, $value, $attributes, $errors);
}

Ya I know, a lot of javascript, but nothing overly complicated just a bunch of flags dictating to recaptcha how the element should be rendered. I added an arbitary flag to the attributes array, so I could still call the same render() methods.  This allows the calling code to tell the widget how it should be rendered. If the context flag is not set to ‘lightbox’ then it simply calls on parent::render() which will default to normal behavior for the class.

Now we just need to add the following code to the lightbox template (the template that your form data is located in):

<?php echo $form['captcha']->renderRow(array('context' => 'lightbox')); ?>

And of course we need to bring in the ReCaptcha js library (view.yml):

javascripts: [http://www.google.com/recaptcha/api/js/recaptcha_ajax.js]

Now, clear symfony cache and click the link to activate your lightbox, it should render your form AND the recaptcha form element. Yay!

In a future post I will write-up how to check lightbox ajax responses using JSON.

jQuery – UI Dialog – Internet Explorer 8 (IE8) Issue with Ajax Response

0

There is an apparent issue with jQuery – Ui Dialog in IE8 where if you submit a form and get an ajax response (in JSON), IE8 will display the response but then quickly load a page with the same exact response. Annoying right? Well the fix is pretty simple. All you need to do is add the following to your form tag:

onclick="return false;"

Now, IE8 won’t attempt to actually load the form action, instead it will stop and render ajax responses as expected.

jQuery – Reverse Each

0

There may be some situations where you need to step through dom elements in reverse order, in this case the following code should help you:


jQuery(jQuery('div.child').get().reverse()).each(function(i) {

    //do stuff

});

Example html:


<div class="parent">

    <div class="child">A</div>

    <div class="child">B</div>

    <div class="child">C</div>

</div>

jQuery – Reset Select Options

3

If you need to reset select options try the following:


var select = jQuery('#someSelect');

select.val(jQuery('options:first', select).val());

Regardless of the first option being blank or not, this will reset the currently selected option to first option. In my opinion it’s always good practice to have a blank first option so the user can easily see it has been reset.

Javascript – JQuery – Check if Form Inputs were Selected

0

If you have a list of checkboxes or radio buttons and want to see if any of them were selected, JQuery makes it simple:

if (!(jQuery("input[@name=<input_name>]:checked").length)) {
    alert('Please select something!');
    return false;
}

return true;

Simply replace <input_name> with the name of your checkboxes/radio buttons. Calling code example:

<form action="someFile.php" method="post" onSubmit="return validateCheckboxes();">

    <input type="checkbox" id="checkbox_id_1" name="checkboxIds[]" value="1"/>
    <input type="checkbox" id="checkbox_id_2" name="checkboxIds[]" value="2"/>
    <input type="checkbox" id="checkbox_id_3" name="checkboxIds[]" value="3"/>
    

So the final javascript would like like:

function validateCheckboxes()
{
    if (!(jQuery("input[@name=checkboxIds]:checked").length)) {
        alert('Please select something!');
        return false;
    }
}
return true;

You can also use specific dom ids, but if you are iterating over a list and echoing out checkboxes/radio buttons I wouldn’t recommend it, as demonstrated above you can hook into multiple inputs by using name.

JQuery is your friend

0

JQuery is a pre-packaged, pre-tested javascript api which will greatly improve the lives of any devs having to deal with javascript in any way. It allows for easy access to dom elements, for example:

Before

var someId = document.getElementById('someId');

After

var someId = $('someId');

Another example in Jquery’s ease of use is hiding/displaying dom elements, for example:

Before

document.getElementById('someId').style.display = 'none';
document.getEelmentById('someId').style.display = 'block';

After

$('someId').hide();
$('someId').show();

As you can see, JQuery greatly reduces the amount of work needed to accomplish seemingly easy tasks. If that isn’t enough to sell you on it as being a great api, consider this; JQuery is also cross-browser tested! So you can rest assured that whatever javascript you implement on your projects will work in most currently supported browsers.

Visit JQuerys website for more info.

Go to Top