0

I have a simple widget that needs its width and height set by the user, so that it is displayed properly on the blog.

The thing is: on the Administrator/Appearance/Widgets page, if the admin user puts something like "400px" on the width, it works perfectly. But what if the user puts "xxxx"?

Is there any way that I can fire some javascript when the user presses the "Save" button, so as to inform the user that the data is invalid? I looked all around for hooks on the save button, or ways to intercept the submit, but found nothing.

Am I looking at this problem from a wrong perspective? Is there a better way to do this?

Thanks in advance.

  • I'd suggest only storing the numeric value and provide a checkbox or dropdown to determine whether to use pixels or a percentage(or if only ever px, just add that when you run the display code). A numeric value alone is easier validate. – t31os Apr 23 '13 at 8:49
2

@tf is almost there, I think. You can use JS on your widget's admin form, as I've done it before (though not for validation).

Within your widget's constructor, add an action:

add_action( "admin_print_scripts-widgets.php", array( __CLASS__, 'register_my_validation_script' ) );

Then create the corresponding function inside your widget's class:

function register_my_validation_script() {
    wp_enqueue_script( 'my-script-handle', plugins_url( '/my-validation-script.js', __FILE__ ), array( 'jquery' ), '1.0' );
}

This assumes your JS is a script (my-validation-script.js) inside your plugin's directory.

Within that JS script is your jQuery to execute your validation. This is where the pseudo code begins...

jQuery(document).ready(function($) {
    $('.widget-control-save').on('click', function() {
// check this is the right widget - probably using something like $(this).closest('form').width-field...
// validate stuff
    });
});
  • 1
    There's little point in registering a script for a single call, just outright do the enqueue for single use scripts. Additionally, as of jQuery 1.7 live is deprecated and should be replaced with on. – t31os Apr 23 '13 at 8:47
  • True, answer edited. – vancoder Apr 23 '13 at 16:28
1

It is a bit tricky to get the ID fropm the form because it is created dynamically. Normally I use this JS to trigger an event when the save button is pressed:

jQuery(document).ready(
    function($) {
        $( '.widget-control-save' ).on( 'click',
            function() {
                // grab the ID of the save button
                var saveID   = $( this ).attr( 'id' );

                // grab the 'global' ID
                var ID       = saveID.replace( /-savewidget/, '' );

            }
        );
    }
);

You are a good guy and so you use get_field_id() and get_field_name() in you widget code, hm!?

printf(
  '<input type="text" id="%s" name="%s" value="%d" />',
  $this->get_field_id( 'width' ),
  $this->get_field_name( 'width' ),
  (int) $instance['width']
);

The ID of your input field is something like your-widget-name-[number]-width. The problem is the number, it differs everytime you add or remove a widget to/from the sidebar. In the JS above, the variable ID now got the value your-widget-name-[number] (e.g. your-widget-name[2]). So you just have to add -width to the ID and can grab the value of the input field

var width = $( '#' + ID + '-width' ). val();
// validate the value of the input field with parseInt() or something else

But if I expect a number, then I would not let the user input chars. It's not a problem to prevent the user from typing chars.

add_filter( 'widget_form_callback', 'prevent_char_input', 1, 2 );

function prevent_char_input( $instance, $object ) {

// assuming your widgets id is 'foo_widget'
if ( 'foo_widget' !== $object->id_base || ! is_integer( $object->number ) )
    return $instance;

echo "
<script>
  jQuery(document).ready( function($) {

    var input = $( '#widget-{$object->id}-width' );

    input.keydown(function(event) {
        // Allow: backspace, delete, tab, escape, and enter
        if ( event.keyCode == 46 || event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 27 || event.keyCode == 13 ||
             // Allow: Ctrl+A
            (event.keyCode == 65 && event.ctrlKey === true) ||
             // Allow: home, end, left, right
            (event.keyCode >= 35 && event.keyCode <= 39)) {
                 // let it happen, don't do anything
                 return;
        }
        else {
            // Ensure that it is a number and stop the keypress
            if (event.shiftKey || (event.keyCode < 48 || event.keyCode > 57) && (event.keyCode < 96 || event.keyCode > 105 )) {
                event.preventDefault();
            }
        }
    });

  } );</script>";

    return $instance;
}

So what we do here is, printing some inline script. The PHP function checks everytime when a html form inside a widget is printed, if the widget name match and if the widget number is an integer. We use the object propperties id_base and id. The id_base is the id you use when registering the widget. The id is the widget-id plus the number in the sidebar (e.g. foo_widget-2).

Best practise is to avoid the inline script. You can create a jQuery extension and enqueue it into the footer. This reduce the inline script to $( '#widget-{$object->id}-width' ).numbersOnly(); and in the javascript something like:

(function( $ ){

  $.fn.numbersOnly = function() {

    this.keydown(function() {
      [... code here ...]
    });

  };
})( jQuery );

I hope this helps you a bit to find the best solution.

0

This is not WP-specific.

Your widget most likely already has a form. That form has a name/ID (if not, give it one).

What you want to do is check onsubmit of the form for certain conditions.

Suppose that is your form:

<form name="myWidgetForm" ... >
    <input type="number" name="width" />
    <input type="number" name="height" />
    ...
    <input type="submit" value="Save" />
</form>

So first change the form as follows:

<form name="myWidgetForm" ... onsubmit="return validateMyWidgetForm()">

Then provide the following JavaScript function (either in a separate JS file that has to be enqueued, or hard-coded):

Plain JavaScript

function validateMyWidgetForm() {
    var msg = "";

    if (document.forms["myWidgetForm"]["width"].value < 400)
        msg = msg + "The value of 'width' has to be greater than 400.\n";

    if (document.forms["myWidgetForm"]["height"].value < 600)
        msg = msg + "The value of 'height' has to be greater than 600.\n";

    ...

    if ("" != msg) {
        alert(msg);
        return false;
    }
    return true;
}

Note: The above function is not copy-and-paste-ready, but for demonstration purposes only.


Alternative jQuery version

function validateMyWidgetForm() {
    var msg = "";

    if (jQuery('#myWidgetForm #width').val() < 400)
        msg = msg + "The value of 'width' has to be greater than 400.\n";

    if (jQuery('#myWidgetForm #height').val() < 600)
        msg = msg + "The value of 'height' has to be greater than 600.\n";

    ...

    if ("" != msg) {
        alert(msg);
        return false;
    }
    return true;
}
  • @t f, thanks for the incredibly fast answer! The way wordpress works, the form name is not in my control. The widget function "form ($instance)" only gives me control of a div inside the form. I am now searching for a way to create a name for the form and to intercept the save button - that is also not inside my control. – tuliomir Apr 22 '13 at 20:03
  • I haven't developed any widgets so far, but both giving the form a name and defining the onsubmit attribute is also possible by jQuery (if not during the widget creation process). – tfrommen Apr 22 '13 at 20:19
  • Well, thanks, t f, for the ideas. But any attempt at javascript on my widget's admin form completely breaks the whole Administrator/Appearance/Widgets page. I still believe it is possible, but it seems I will have to deal with a lot of existing Ajax before I'm able to make it. – tuliomir Apr 22 '13 at 20:46
  • @tf The problem with the widgest on the widgets page is, the IDs of each form is generated dynamically. So you cannot really predict what ID the form will have. – Ralf912 Apr 23 '13 at 20:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.