submit<X> method

  1. @override
FutureOr<FormSubmitResult<X>> submit<X>(
  1. BuildContext context, {
  2. FutureOr<X?> submit()?,
  3. bool? skipIfUnmodified,
})
override

Submits this form, including subforms, and returns the result

Implementation

@override
FutureOr<FormSubmitResult<X>> submit<X>(BuildContext context,
    {FutureOr<X?> submit()?, bool? skipIfUnmodified}) async {
  skipIfUnmodified ??= false;

  final start = DateTime.now();
  startSubmission();
  var result = FormSubmitResultBuilder<X>.start(this);

  for (final entry in readyChecks.entries) {
    log.info("Awaiting ready check: ${entry.key}");
    if (entry.value.isActive) {
      await entry.value.future;
      log.info("Finished ready check: ${entry.key}");
    } else {
      log.info("Found ready check, but it was not active: ${entry.key}");
    }
  }

  final hasChanges = skipIfUnmodified != true || isModified;

  /// first, validate all the way down the chain:
  final validationErrors = await validate(skipIfUnmodified: skipIfUnmodified);
  if (validationErrors.isNotEmpty && hasChanges) {
    result
      ..validationErrors = validationErrors
      ..resultType = ResultType.error
      ..message = "Validation error";
    return result.end();
  }

  final copy = [..._subforms];
  for (final subform in copy) {
    try {
      log.info(
          "Submitting subform ${subform!.name}: modified=${subform.isModified} ${skipIfUnmodified != true ? '(saving anyway)' : ''}");

      ///
      /// Submitting each subform
      ///
      final subformResult =
          await subform.submit(context, skipIfUnmodified: skipIfUnmodified);
      log.info("Done with ${subform.name} subform ${subform.name}");
      result.subforms[subform.name] = subformResult;
      if (subformResult.isError) {
        log.warning(
            "Early termination from subform ${subform.name}: ${subformResult.message}");
        result
          ..resultType = ResultType.error
          ..message =
              "Subform error ${subform.name}: ${subformResult.message}";

        return result.end();
      }
    } catch (e) {
      result.subforms[subform!.name] = FormSubmitResult.error(this, e);
      result
        ..resultType = ResultType.error
        ..message = "$e";
      return result.end();
    }
  }

  try {
    // Run onSubmits
    final hooks = [..._submitHooks.entries];
    if (skipIfUnmodified != true || isModified) {
      for (final hook in hooks) {
        log.info("Executing hook: ${hook.key}");
        final hookResult = await hook.value(this, result);
        result.submitHooks[hook.key] = hookResult;
        if (!hookResult.isSuccessful) {
          result
            ..resultType = ResultType.error
            ..message =
                "Failed submit hook ${hook.key}: ${hookResult.message}";
          return result.end();
        }
        log.info("Hook: ${hook.key}: $hookResult");
      }
      X? submitResult = (await submit?.call());
      result
        ..value = submitResult
        ..resultType = ResultType.success;
    } else {
      result..resultType = ResultType.skipped;
    }
    return result.end();
  } catch (e, stack) {
    if (e is BadRequestException) {
      result.validationErrors = e.validationErrors.groupBy((e) => e.path);
      this.updateErrors(e.validationErrors, source: AttributeSource.model);
      result.message = "Validation Errors";
    } else {
      result.message = "Error submitting form";
      log.info(e);
      log.info(stack);
      SunnyHud.error(context, "Error submitting form");
    }
    result.resultType = ResultType.error;
    return result.end();
  } finally {
    endSubmission();
    log.info(
        "Form submitted in ${DateTime.now().difference(start).inMilliseconds}");
  }
}