0

Let's say I have a form with 2 IntFields. How can I validate IntField B depending on the input in IntField A? e.g. if A == 1, B can only be within 0-30; if A == 2, B can only be within 0-50; else B can be any other numbers

From all I can google, I can only find IntValidator which validates the field only without the ability to link to another field. No examples that I can find that shows how I can update the min/max values in the IntValidator, nor any custom Validator which can take the value of another field such that validation can change according to change of value in another field...

enamldef IntFieldsWindow( Window ):

    Container:
        Form:
            padding=0
            Label:
                text = 'Field A'
            IntField: fld_a:
                value = 0
            Label:
                text = 'Field B'
            IntField: fld_b:
                value = 0

After some tests, it is actually possible to pass fld_a to a custom validator, then get the fld_a.value in the validate function, finally set the custom validator to fld_b. Not sure if it is the way to do such validation though.

Porz
  • 183
  • 3
  • 15

1 Answers1

0

One way is to break the data out into a model and have it validate the members using an observer that is called when either member changes.

Then make the IntField bind to the model value (using <<) and update the model value using a notification handler (::) that catches and reports validation errors.

For example:

from atom.api import Atom, Int, observe
from enaml.stdlib.fields import IntField
from enaml.widgets.api import Window, Container, Label, Form


class Model(Atom):
    a = Int()
    b = Int()

    @observe('a', 'b')
    def _validate(self, change):
        # When a or b is changed validate the model state
        a, b = self.a, self.b
        if a == 1:
            if b < 0 or b > 30:
                raise ValueError("B is out of range")
        elif a == 2:
            if b < 0 or b > 50:
                raise ValueError("B is out of range")


enamldef Main(Window):
    attr model = Model()
    Container:
        Form:
            padding=0
            Label:
                text = 'Field A'
            IntField: fld_a:
                value << model.a
                value ::
                    error.text = ''
                    try:
                        model.a = change['value']
                    except ValueError as e:
                        error.text = str(e)
            Label:
                text = 'Field B'
            IntField: fld_b:
                value << model.b
                value ::
                    error.text = ''
                    try:
                        model.b = change['value']
                    except ValueError as e:
                        error.text = str(e)
        Label: 
            text << 'A:{} B:{}'.format(model.a, model.b)
        Label: error:
            pass

Notice the that the label outputting the model values never has an invalid state! The validator on the model will ensure this never happens.

frmdstryr
  • 20,142
  • 3
  • 38
  • 32