简体   繁体   中英

Custom validation rule with knockout.js

I'm having trouble getting a custom validation rule setup with knockout.js for checking if a username already exists. From my understanding, if the return is true then there are no errors, otherwise an error is set.

Here's an example of custom validation

//val is the username in question and searchType is the type of search(username or email)
function checkValue(val, searchType){
  if(searchType == 'userName'){
    $.post("/users/check_if_exists",{ 'type':'username', 'value': val },function(data) {
        var info = JSON.parse(data);
        if(info.username_availability == "available"){
            return searchType;
                            //I know this is working because I've alerted the searchtype here and it displays properly
        }
        else{
            return "unavailable";
        }
    });
  }
} 

ko.validation.rules['checkIfExists'] = {
    validator: function (val, searchType) {
        return searchType == checkValue(val, searchType); //if the username is availble, the searchType is returned back so it would return searchType == searchType which should be true meaning there are no errors
    },
    message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();

I've checked the network tab and the POST is returning the correct value. If the value is available, I return the searchType. That way, it compares searchType == searchType which should be true. However, that's not the case.

Is there any other way to accomplish what I'm trying to do?

update

Here's what I have as of now

function checkValue(val, searchType, callback) {
     var callback = function(data) {
        return true;
    }
    $.post("/users/check_if_exists", { 'type':'username', 'value': val }, function(data) {
        info = JSON.parse(data);
        if(info.username_availability == "available"){
            callback(true);
        } else {
            callback(false);
        }
    }); 
}

ko.validation.rules['checkIfExists'] = {
    async: true,
    validator: function (val, searchType) {
        alert(checkValue(val, searchType));//returns undefined
        return checkValue(val, searchType);
    },
    message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();

ko.validation calls your validation function. There are two types of validation functions with regards to the way they pass the success/failure state back to ko.validation: the straight-forward return true/false way, or the "async" way.

The async way exists only because $.ajax exists and it's basically just this: instead of returning a value (which is impossible, as you are using an $.ajax call) you have to somehow notify ko.validation after the ajax response gets back to the browser, right?

So the smart people who wrote this library call your validation function with an extra parameter, a function (callback), that you have to call when the response is available.

function checkValue(val, searchType, callback){
  if(searchType == 'userName'){
    $.post("/users/check_if_exists",{ 'type':'username', 'value': val },function(data) {
        var info = JSON.parse(data);
        if(info.username_availability == "available"){
            callback(true);
                            //I know this is working because I've alerted the searchtype here and it displays properly
        }
        else{
            callback(false);
        }
    });
  }
} 


ko.validation.rules['checkIfExists'] = {
    async: true,
    validator: checkValue,
    message: 'This username is taken, please select another.'
};
ko.validation.registerExtenders();

Let me turn your code into something more readable:

function checkValue(val) {
    var callback = function(data) {
        return 'bar';
    }

    $.post('url', 'data', callback); 
}

var x = checkValue('foo');

You are expecting x to be set to 'bar' when that is not the case. I replaced your anonymous function with "callback" so you better understand that returning something from it does not mean "checkValue" will return anything. After that your next problem is the fact that AJAX calls are asynchronous.

A validator function accepts three parameters: the value, extra parameters and a callback function. The callback function parameter is designed to aid you in exactly this situation.

Inside the success callback for the $.post you just have to call that callback function for the validator function passing true/false as a parameter.

function checkValue(val, params, callback) {
    $.post('url', 'data', function(data) {
        if(data === 'bar') {
            callback(true);
        } else {
            callback(false);
        }
    }); 
}

checkValue as you have written it always returns undefined. Invoking "return" from inside of a callback function only sets the return value for that callback function (not the "outer function"). If the validator function expects a return value right away (as knockout appears to do) you won't be able get that data asynchronously.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM