javascriptodooodoo-owl

Invalidate OWL field to prevent save data in Odoo 17


I'm taking the email widget called EmailField to add new features I need. This email field didn't validate the format and it allows you to save the data without validation. So my question here is inside Odoo OWL black magic (Because there are no comments or docs about it) there is anything to invalidate data and prevent the user save?

/** @odoo-module **/
import { useState } from "@odoo/owl";
import { EmailField } from "@web/views/fields/email/email_field";
import { _t } from "@web/core/l10n/translation";
import { useInputField } from "@web/views/fields/input_field_hook";
import { patch } from "@web/core/utils/patch";

patch(EmailField.prototype, {
    setup() {
        super.setup();
        this.state = useState({ isValid: false, errorMessage: "" });
        useInputField({ getValue: () => this.validateEmail() });
    },
    validateEmail() {
        if (this.props.record.data[this.props.name]) {
            if (!this.props.record.data[this.props.name].match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)) {
                this.state.isValid = false;
                this.state.errorMessage = _t("Invalid email");
                this._showErrorMsg();
            }
        } else {
            this.state.isValid = true;
            this.state.errorMessage = "";
        }
        return this.props.record.data[this.props.name] || "";
    },
    _showErrorMsg() {
        this.env.services.notification.add(_t("Invalid email"), { type: "danger" });
    },
});

I extend the Widget and set validations when you write. But still saving the data.


Solution

  • There is an argument in the useInputField hook that parses the value before saving, this guarantees that the validateEmail() would trigger in all scenarios to properly determine if it should raise an error or not. I updated your code and it worked as i'm asuming you would expect...

    /** @odoo-module **/
    import { EmailField } from "@web/views/fields/email/email_field";
    import { _t } from "@web/core/l10n/translation";
    import { useInputField } from "@web/views/fields/input_field_hook";
    import { patch } from "@web/core/utils/patch";
    
    patch(EmailField.prototype, {
        setup() {
            super.setup();
            useInputField({ getValue: () => this.props.record.data[this.props.name] || "", parse: (v) => this.validateEmail(v)});
        },
        validateEmail(v) {
            if (v && !v.match(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/)) { 
                this.props.record.setInvalidField(this.props.name);               
                this._showErrorMsg();                
            }
    
            return v
        },
        _showErrorMsg() {
            this.env.services.notification.add(_t("Invalid email"), { type: "danger" });
        },
    });
    

    the key is to use the function setInvalidField()

    this.props.record.setInvalidField(this.props.name);
    

    this is what's going to highlight the field and prevent saving