What a picker accepts: the same rules in the browser, as people choose,
and on the server, in Erabi.Changeset.
@rules Erabi.Rules.new(max: 3, create: true, max_length: 24)
<.tags field={@form[:labels]} options={@labels} rules={@rules} />
changeset
|> cast(params, [:labels])
|> Erabi.Changeset.validate_choice(:labels, @rules, options: @labels)The rules:
:required- at least one value;:min,:max- how many values, for a picker of several;:create- whether a value that is not an option may be chosen (typed, as a new tag, or kept as text in a combobox); without it, every value must be an option;:min_length,:max_length- the length of a new value, in characters (graphemes);:pattern- a regular expression a new value must match, whole. It runs in the browser too (RegExpwith theuflag), so keep to what both have: classes, ranges,\d,\w,\s,\p{L}, counts and alternatives.
A picker of several never posts the same value twice.
The browser checks the rules as people choose: it does not add a value
past :max, and says why it cannot create a value. The server checks
them again: the browser is a convenience, and a form can be posted by
anything.
Summary
Functions
Checks the values that a picker posts (texts, see
Erabi.Option.params/1) against the rules: :ok, or the first reason
they are refused. known is the values of the options, or :any when
the options are not all known here (a search): then values are not
refused for not being options.
Checks a value that is not an option, as a person creates it: :ok, or
why it cannot be.
Rules from a keyword list (see the moduledoc), or the rules as they are.
Raises an ArgumentError that says what is wrong.
Types
Why values are refused, with what the message needs:
{:required, []}{:too_few, min: n},{:too_many, max: n}{:not_allowed, value: v}- not an option, and:createis off{:too_short, min_length: n, value: v},{:too_long, max_length: n, value: v}{:format, value: v}- a new value that does not match:pattern{:duplicate, value: v}
@type t() :: %Erabi.Rules{ create: boolean(), max: pos_integer() | nil, max_length: pos_integer() | nil, min: non_neg_integer() | nil, min_length: non_neg_integer() | nil, pattern: String.t() | nil, required: boolean() }
Functions
Checks the values that a picker posts (texts, see
Erabi.Option.params/1) against the rules: :ok, or the first reason
they are refused. known is the values of the options, or :any when
the options are not all known here (a search): then values are not
refused for not being options.
iex> rules = Erabi.Rules.new(max: 2)
iex> Erabi.Rules.check(rules, ["a", "b", "c"], ["a", "b", "c"])
{:error, {:too_many, [max: 2]}}
iex> Erabi.Rules.check(rules, ["x"], ["a", "b"])
{:error, {:not_allowed, [value: "x"]}}
Checks a value that is not an option, as a person creates it: :ok, or
why it cannot be.
iex> Erabi.Rules.check_value(Erabi.Rules.new(create: true, max_length: 3), "four")
{:error, {:too_long, [max_length: 3, value: "four"]}}
Rules from a keyword list (see the moduledoc), or the rules as they are.
Raises an ArgumentError that says what is wrong.
iex> Erabi.Rules.new(max: 3)
%Erabi.Rules{max: 3}