···410410pub fn simple_limit_check(min: Int, max: Int, extra: Int) -> LimitCheck {
411411 fn(num_nonempty) {
412412 case max - num_nonempty {
413413- x if x < 0 -> Error(x)
413413+ x if x < 0 -> Error(-x)
414414 _ -> {
415415 int.max(1 - num_nonempty, int.min(extra, max - num_nonempty))
416416 list.fold([1, extra, min], 0, int.max)
···507507 let assert [ListField(field, states, limit_check, widget), ..next_items] =
508508 items
509509510510- // go through all decode all input values. these can have empty rows
510510+ // go through and parse all input values. these can have empty rows
511511 // that were offered to the consumer, but they didn't fill out. we need
512512- // to keep track of those so they can be used when generating the form
513513- // again on error
512512+ // to keep track of those so they can be displayed when generating the form
513513+ // again on error.
514514 let item_results =
515515- list.map(states, parse_list_state(_, definition.parse, definition.stub))
515515+ states
516516+ |> list.map(parse_list_state(_, definition.parse, definition.stub))
517517+ // then we need to check if too many values were submitted, and if so
518518+ // mark the extra ones as having errors
519519+ |> mark_above_max_values_as_invalid(limit_check)
516520517521 // but we don't want them for considering the output of this list field,
518522 // so remove the empty optional fields and just grab the outputs
···587591 stub: a,
588592) -> ListParsingResult(a) {
589593 case state.value, state.requirement {
590590- "", Required -> parse(state.value)
591594 "", Optional -> Ok(stub)
592595 _, _ -> parse(state.value)
593596 }
594597 |> ListParsingResult(state.value, state.requirement, _)
598598+}
599599+600600+fn mark_above_max_values_as_invalid(
601601+ list: List(ListParsingResult(output)),
602602+ limit_check: LimitCheck,
603603+) -> List(ListParsingResult(output)) {
604604+ let count =
605605+ list.fold(list, 0, fn(acc, r) {
606606+ case r.value, r.requirement {
607607+ "", Optional -> acc
608608+ _, _ -> acc + 1
609609+ }
610610+ })
611611+612612+ case limit_check(count) {
613613+ Ok(_) -> list
614614+ Error(num_too_many) -> {
615615+ let max_index = count - num_too_many
616616+617617+ let #(mapped_results, _) =
618618+ list.fold(list, #([], 0), fn(acc, r) {
619619+ let #(results, i) = acc
620620+ case r.value, r.requirement, i >= max_index {
621621+ "", Optional, _ -> #([r, ..results], i)
622622+ _, _, False -> #([r, ..results], i + 1)
623623+ v, r, True -> #(
624624+ [
625625+ ListParsingResult(v, r, Error("exceeds maximum allowed items")),
626626+ ..results
627627+ ],
628628+ i + 1,
629629+ )
630630+ }
631631+ })
632632+633633+ mapped_results |> list.reverse
634634+ }
635635+ }
595636}
596637597638/// Add a list field to a form, but with no limits on the number of values that
+45
formz/test/formz_test.gleam
···690690 Valid("2", Optional),
691691 ])
692692}
693693+694694+pub fn limited_list_too_many_test() {
695695+ let f = {
696696+ use a <- formz.limited_list(
697697+ formz.limit_between(2, 3),
698698+ field("a"),
699699+ integer_field(),
700700+ )
701701+702702+ formz.create_form(a)
703703+ }
704704+705705+ // straight up too many
706706+ f
707707+ |> formz.data([
708708+ #("a", "1"),
709709+ #("a", "2"),
710710+ #("a", "3"),
711711+ #("a", "4"),
712712+ #("a", "5"),
713713+ ])
714714+ |> formz.decode
715715+ |> get_form_from_error_result
716716+ |> formz.get_states
717717+ |> should.equal([
718718+ Valid("1", Required),
719719+ Valid("2", Required),
720720+ Valid("3", Optional),
721721+ Invalid("4", Optional, "exceeds maximum allowed items"),
722722+ Invalid("5", Optional, "exceeds maximum allowed items"),
723723+ ])
724724+725725+ // too many but with an empty value that should be skipped
726726+ f
727727+ |> formz.data([#("a", "1"), #("a", ""), #("a", "3"), #("a", "4"), #("a", "5")])
728728+ |> formz.decode
729729+ |> get_form_from_error_result
730730+ |> formz.get_states
731731+ |> should.equal([
732732+ Valid("1", Required),
733733+ Valid("3", Required),
734734+ Valid("4", Optional),
735735+ Invalid("5", Optional, "exceeds maximum allowed items"),
736736+ ])
737737+}