4

Using jQuery validation plugin, I have been trying to retrieve a form's input field value, concatenate it with some url prefix to make a REST url, and then make a GET request to the resulting url via remote method.

Below's the REST interface's method (server side is java)

@Path("/user")
public interface UserResource {

    @GET
    @Path("/registered/email/{value}")
    public boolean isRegistered(@PathParam("value") String value);
}

And here's what the input field to be validated looks like

<form id="registerForm" action="/register" method="POST">
    <input class="form-control" id="email" name="email" type="email" value='${email}' required/>
    ...
</form>

And then the jQuery validation script;

$('body #registerForm').validate({
    rules : {
        'email': {
            required: true,
            email: true,
            remote: "/user/registered/email/" + $(this).find('#email').val()
        },
    },
    messages : {
        'email': {
            required: 'Please enter your email address',
            email: 'Please provide a valid email address',
            remote: 'Email has already been taken',
        },
    },
});

Please note how the value passed to the remote method is simply the REST url because according to http://jqueryvalidation.org/remote-method/, the default request type is GET... Note also how dataType and data are not specified because they are not necessarily needed for this case.

THE GOAL: ... Now, say the email entered by the user is username@email.com I would normally expect the resulting url to look like the following;

http://localhost:8080/user/registered/email/username@email.com

THE PROBLEM: ... but instead here's what I get;

http://localhost:8080/user/registered/email/?email=username@email.com

QUESTION: ... Notice the ?email= before username@email.com in the url... I wonder why the result of $(this).find('#email').val() is being concatenated as a query param?... Please can somebody explain to me why this is happening?.. And also how do I solve this problem?

Thanks.

SourceVisor
  • 1,868
  • 1
  • 27
  • 43
  • I think is because the plugin gets the name of validation rule to pass the parameter. – pabgaran May 12 '15 at 14:22
  • This is not an answer, but, you'd be better of using the `submitHandler` and making your own ajax call etc. – lshettyl May 12 '15 at 14:24
  • have you tried setting email: false, in stead? I mean, how does it know to make the query string ?email=username@email.com – Jacob Finamore May 12 '15 at 14:28
  • 1
    The value of the field is simply `$('#email').val()`. `$(this).find()` is completely unnecessary. And using a query string, `?field="value"&field2="value2"....`, is exactly how data is sent with a `GET` request. You would not use a URL segment for picking this value up on the server-side, just use the `GET` array. – Sparky May 12 '15 at 14:49
  • @Sparky, thanks for the heads-up... I was thinking the GET array might be a way out too. I'll give it a shot right-away and give feed back afterwards – SourceVisor May 12 '15 at 14:58
  • @LShetty, `ajax` definitely worked for me, even though I would have really preferred using jQuery validation's `remote` method, however Dev Timelines are not such good friends to me at this time – SourceVisor May 12 '15 at 16:46
  • `remote` is just using `.ajax()` so whatever you're doing with `.ajax()`, you could have achieved the same with `remote`. – Sparky May 12 '15 at 17:15

4 Answers4

2

QUESTION: ... Notice the ?email= before username@email.com in the url... I wonder why the result of $(this).find('#email').val() is being concatenated as a query param?... Please can somebody explain to me why this is happening?.. And also how do I solve this problem?

By default, a query string, ?field="value"&field2="value2"...., is exactly how data is sent along with a GET request. Typically, you would not use a URL segment for picking up this value on the server-side, just use the GET array.

The jQuery Validate plugin's remote method uses the same options as jQuery .ajax(). Referring to the .ajax() documentation...

data
Type: PlainObject or String or Array
Data to be sent to the server. It is converted to a query string, if not already a string. It's appended to the url for GET-requests. See processData option to prevent this automatic processing. Object must be Key/Value pairs. If value is an Array, jQuery serializes multiple values with same key based on the value of the traditional setting (described below).

...

processData (default: true)
Type: Boolean
By default, data passed in to the data option as an object (technically, anything other than a string) will be processed and transformed into a query string, fitting to the default content-type "application/x-www-form-urlencoded". If you want to send a DOMDocument, or other non-processed data, set this option to false.


OP Title: JQuery Validation - How to correctly retrieve form field value in “remote” method?

To get the value of the field, simply select the field and attach it to a jQuery .val(). There is no need to use $(this).find(...

$('#email').val()

Try this...

rules : {
    'email': {
        required: true,
        email: true,
        remote: {
            url: "/user/registered/email/" + $('#email').val(),
            processData: false
        }
    },
},
Sparky
  • 98,165
  • 25
  • 199
  • 285
  • using `processData: false` did not work for my REST request. Because of my timelines, I ended up reverting to using .ajax() instead of the `remote` method. – SourceVisor May 12 '15 at 16:43
  • @Teejay, that doesn't make any sense. `remote` is using `.ajax()` so whatever you're doing with `.ajax()`, you could have achieved the same with `remote`. – Sparky May 12 '15 at 17:14
  • I agree with you, except with remote I cldn't pass flat URLs like `*/path/param/value`... instead it had to append query strings like `*/path/?param=value`... which isn't exactly what I was trying to achieve (and going by your suggestion `processData: false` did not help either) – SourceVisor May 13 '15 at 09:33
  • or is there something you're pointing at that I don't seem to understand yet?... I'm absolutely open to learning – SourceVisor May 13 '15 at 09:46
  • @Teejay, I've never had to use the `processData` option myself and I cannot see what you've done with `.ajax()`. My point is that the `remote` method internally uses jQuery `.ajax()` and accepts the same options, so whatever you're doing now that works, can also be done using `remote`. In other words, there is no reason to use `.ajax()` instead of `remote`. Whatever you've done with the former, can also be done using the latter. – Sparky May 13 '15 at 14:32
  • I've come back after a while to accept this as the answer because it surely breaks down and explains what I needed to know. – SourceVisor Aug 12 '15 at 07:15
2

THE GOAL: ... Now, say the email entered by the user is username@email.com I would normally expect the resulting url to look like the following;

http://localhost:8080/user/registered/email/username@email.com

THE PROBLEM: ... but instead here's what I get;

http://localhost:8080/user/registered/email/?email=username@email.com

There are two issues here. The first is that the validate method resolves the url path as it is executed - it is not reexamined dynamically by default. And when it is run, basically when the form is rendered, your email input field is empty. The path is thus resolved to 'http://localhost:8080/user/registered/email/' + '' (the static string you started with, concatenated with the empty string from the empty input field).

The second issue is that jQuery.validate's remote method by default sends along the validated field's 'name' and 'value' attributes as query parameters - which is, of course, not the REST way of doing things. these are flattened into '?email=username@email.com', which is placed after the rest of the URL as it was resolved in the first step.

To get around the first issue, and build a REST-worthy path, you have to wrap your URL building in a function, which will be executed each time validation is requested on that input.

$('body #registerForm').validate({
    rules : {
        'email': {
            required: true,
            email: true,
            remote: function() {
                return '/user/registered/email/' + $('#email').val()
            }
        }
    }
});

This will result in a proper REST API url, though it will still have the query string appended to it. It will look something like this:

http://localhost:8080/user/registered/email/username@email.com?email=username@email.com

Granted, this is ugly, but chances are your API will silently ignore the query string, and execute as expected.

But in order to get a cleaner, more RESTful url, you need to reset the data attribute of the ajax call. You do that by having your remote function from step one return an object, with the url string from before as the url parameter, and setting a data parameter to an empty string.

$('body #registerForm').validate({
    rules : {
        'email': {
            required: true,
            email: true,
            remote: function() {
                return {
                    url: '/user/registered/email/' + $('#email').val(),
                    data: ''
                }
            }
        }
    }
});

This will result in the desired, RESTful url

http://localhost:8080/user/registered/email/username@email.com

Cernael
  • 91
  • 5
1

I used this code to work-around the REST service issue:

$("#mailingAddress").rules("add", {
    required: true,
    remote: function () { 
        var r = {
            url: "/Api/Address/ValidateAddressSimple/" + $("#mailingAddress").val(),
            type: "post",
            cache: false,
            dataFilter: function (response)
            {
                return response;
            }
        };
        return r;
    },
    messages: {
        remote: "* not valid"
    }
});

taken from this post: https://stackoverflow.com/a/22467664

Community
  • 1
  • 1
Russell Munro
  • 479
  • 5
  • 9
0

You are making a get request to what looks like a folder or location on your website. You need to provide a script that does the checking. So your remote url should be something like "/user/registered/email/check_email.php".

Also, the whole idea of a GET request is that the parameters are passed as name/value pairs that are tacked onto the query string after the "?" separator. See http://www.w3schools.com/tags/ref_httpmethods.asp. You are not providing an actual remote script, and are not providing a parameter name for your value, so you just get the url + "?" + your value.

Finally, I would recommend you go with the POST method. In the resource you provided a link for, look at the second example. It shows you how to specify POST.

Does all this make sense?

  • The REST resource isn't my code and could have been used in more places than I know, so I'm not sure I can change it to a POST method... What I basically need is how to construct the url to look like... http://localhost:8080/user/registered/email/username@email.com ... – SourceVisor May 12 '15 at 14:50
  • Also, the request is not to a folder... and because it's a GET request to a REST url, i'm not sure using query params like ***?name1=value1&name2=value2 in a REST url is best practice, don't you think so? – SourceVisor May 12 '15 at 14:51
  • A URL of "/user/registered/email/" does not make sense for the URL of a resource that is going to be capable of responding to a remote call. Remote is for passing information to a resource and having that resource on the server send you back a true or false. The resource should be something like a script (ex: "MyEmailChecker.php" ), and unless you are going to use post, then you have to use GET, which means the query string has to be something in the format of "MyEmailChecker.php?EmailAddress=joe@tamu.edu". –  May 12 '15 at 15:34
  • I agree in principle with Gilchrist; the `remote` URL should just be a script where the GET or POST array is examined. However, using URI segments to pass data to the server is not uncommon at all. CodeIgniter's URI's are set up this way too; `/controller/method/parameter1/parameter2/`, which might look like, `/shopping/view/shirt/red` where all red shirts are displayed thanks to passing `shirt` and `red` into the `view` method of the `shopping` controller. – Sparky May 12 '15 at 16:24