Check data in model with rules

Hello everybody,

i need a function who checks zipcode with cities in a database and give back the city name in a form input field.

So i have set rules in my model like:

    public function rules()
    {
        return [
            ...
            [['zipcode'], 'getCity', 'when' => function ($model, $attribute) {
                return $model->{$attribute} !== $model->getOldAttribute($attribute);
            }
            ],
            ...
        ];
    }

And i have a function called getCity in the model like:

    public function getCity($attribute, $params) {
        $city=checkZipcodeDatabase($this->$attribute);
        if($city) {
            // there will be a function who search the zipcode 
            // in a data table and returns the city name
            $this->city=$city // sets the form field city with found city name from database;
            return true;
        } else {
            $this->addError('city', 'city is wrong'); //sets the error from form field city
            return false;
        }
    }

When the user add a zipcode in the form field the function must look in a database if the zipcode and the city exists and give the city name back. if there is nothing, the function give false back.

If there is a city name found, the value of the city field in the form must set to the city name. If there is nothing there must shown a error at the city form field. But at the moment, the error message only will be added to the city attribute. But the message will no shown at the form field.

I can see this if i debugging with browser:
dbug

Is this possible to set the value form a form field from another field when using rules?

Thanks for any inspirations :slight_smile:

You can achieve it in at least two ways. First, server side way, if you set your model attribute to the city name you have got with your db query (ran within zipcode field rule for example) and then render the view again, it will be there. Second, JS way, you can respond on the JS afterValidate event, send some ajax request with zip code and fill your form field with the city name.

See https://www.yiiframework.com/doc/guide/2.0/en/input-form-javascript#aftervalidate

Thank you BartQ76.

I don’t know how i can refresh the view after validation. You mean that i completly reload the site or can i only reload the form?

And the second way with JS means for example?

// JS afterValidate function
$('.validate-form').on('afterValidate', function (event, messages, errorAttributes) {
    //load the city name from db with a ajax function
    return false;
});

Can you give me a few more tips? Thank you very much…

In the simplest way you can reload whole page (or form via pjax). Think the form lifecycle way on server side. In pseudo-code:

load form model
// zipcode present but city NOT
if(form->zipcode && !form->city) {
  load city from db
  update form model -> city
  return render form 
}
// zipcode AND city present
if(form->zipcode && form->city) {
  procceed form
  save data etc.
  return render success :))
}

You can do it by something like this:

$this->registerJs(<<<JS
    $('#yourform').on('afterValidateAttribute', function (e, a, m) {
    // check if it is zipcode attribute
    // ...
    // if so, do some ajax request
    // ...
    // update your 'city' field value
    $("#yourcityformfield").val(//ajax response)
    });
JS);

Have you checked exists validator? Seems like that is what you are looking for.

1 Like

Thank you all.

I found a solution for me using an ajax function. it works now.