diff --git a/changelog/67_UNRELEASED_xxxx-xx-xx.md b/changelog/67_UNRELEASED_xxxx-xx-xx.md
index 987ed3e5..fe9454d4 100644
--- a/changelog/67_UNRELEASED_xxxx-xx-xx.md
+++ b/changelog/67_UNRELEASED_xxxx-xx-xx.md
@@ -61,6 +61,7 @@
### General
+- Optimized form validation: Save / submit buttons are now not disabled when the form is invalid, the invalid / missing fields are instead highlighted when trying to submit / save the form (making it more obvous which fields are invalid / missing exactly)
- Fixed an server error (on every page) when not having any quantity unit
### API
diff --git a/public/js/grocy.js b/public/js/grocy.js
index 34122eb2..61121dc3 100644
--- a/public/js/grocy.js
+++ b/public/js/grocy.js
@@ -382,7 +382,7 @@ window.FontAwesomeConfig = {
}
Grocy.FrontendHelpers = {};
-Grocy.FrontendHelpers.ValidateForm = function(formId)
+Grocy.FrontendHelpers.ValidateForm = function(formId, reportValidity = false)
{
var form = document.getElementById(formId);
if (form === null || form === undefined)
@@ -390,17 +390,14 @@ Grocy.FrontendHelpers.ValidateForm = function(formId)
return;
}
- if (form.checkValidity() === true)
+ $(form).addClass('was-validated');
+
+ if (reportValidity)
{
- $(form).find(':submit').removeClass('disabled');
- $(form).find('.keep-disabled').addClass('disabled');
- }
- else
- {
- $(form).find(':submit').addClass('disabled');
+ form.reportValidity();
}
- $(form).addClass('was-validated');
+ return form.checkValidity();
}
Grocy.FrontendHelpers.BeginUiBusy = function(formId = null)
diff --git a/public/viewjs/batteryform.js b/public/viewjs/batteryform.js
index 973ed23c..e3f7fdf5 100644
--- a/public/viewjs/batteryform.js
+++ b/public/viewjs/batteryform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("battery-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/batterytracking.js b/public/viewjs/batterytracking.js
index b7b64844..526349ff 100644
--- a/public/viewjs/batterytracking.js
+++ b/public/viewjs/batterytracking.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("batterytracking-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/choreform.js b/public/viewjs/choreform.js
index ec8fe1da..fce5e152 100644
--- a/public/viewjs/choreform.js
+++ b/public/viewjs/choreform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("chore-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/choretracking.js b/public/viewjs/choretracking.js
index 15c5dd03..e80c638c 100644
--- a/public/viewjs/choretracking.js
+++ b/public/viewjs/choretracking.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("choretracking-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/consume.js b/public/viewjs/consume.js
index a4d9d867..6f14174e 100644
--- a/public/viewjs/consume.js
+++ b/public/viewjs/consume.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("consume-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
@@ -145,6 +150,11 @@ $('#save-mark-as-open-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("consume-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/equipmentform.js b/public/viewjs/equipmentform.js
index b42c3e79..46822a24 100644
--- a/public/viewjs/equipmentform.js
+++ b/public/viewjs/equipmentform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("equipment-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/inventory.js b/public/viewjs/inventory.js
index 0500ab31..7fe93ba5 100644
--- a/public/viewjs/inventory.js
+++ b/public/viewjs/inventory.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("inventory-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/locationform.js b/public/viewjs/locationform.js
index a864d947..98fc54af 100644
--- a/public/viewjs/locationform.js
+++ b/public/viewjs/locationform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("location-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/mealplan.js b/public/viewjs/mealplan.js
index 16a3ef36..fd8bea51 100644
--- a/public/viewjs/mealplan.js
+++ b/public/viewjs/mealplan.js
@@ -497,6 +497,11 @@ $('#save-add-recipe-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("add-recipe-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
@@ -543,6 +548,11 @@ $('#save-add-note-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("add-note-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
@@ -591,6 +601,11 @@ $('#save-add-product-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("add-product-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
@@ -645,6 +660,11 @@ $('#save-copy-day-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("copy-day-form", true))
+ {
+ return;
+ }
+
if (document.getElementById("copy-day-form").checkValidity() === false) //There is at least one validation error
{
return false;
@@ -727,9 +747,9 @@ $('#add-product-form input').keydown(function(event)
$(document).on("keydown", "#servings", function(e)
{
- if (event.keyCode === 13) //Enter
+ if (e.keyCode === 13) //Enter
{
- event.preventDefault();
+ e.preventDefault();
if (document.getElementById("add-recipe-form").checkValidity() === false) //There is at least one validation error
{
diff --git a/public/viewjs/mealplansectionform.js b/public/viewjs/mealplansectionform.js
index b926be4b..ec14e8af 100644
--- a/public/viewjs/mealplansectionform.js
+++ b/public/viewjs/mealplansectionform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("mealplansection-form", true))
+ {
+ return;
+ }
+
var jsonData = $('#mealplansection-form').serializeJSON();
Grocy.FrontendHelpers.BeginUiBusy("mealplansection-form");
diff --git a/public/viewjs/productbarcodeform.js b/public/viewjs/productbarcodeform.js
index 7eca45f6..e1b3f6f4 100644
--- a/public/viewjs/productbarcodeform.js
+++ b/public/viewjs/productbarcodeform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("barcode-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/productform.js b/public/viewjs/productform.js
index cf77917e..6f2b4967 100644
--- a/public/viewjs/productform.js
+++ b/public/viewjs/productform.js
@@ -82,6 +82,11 @@ $('.save-product-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("product-form", true))
+ {
+ return;
+ }
+
var jsonData = $('#product-form').serializeJSON();
var parentProductId = jsonData.product_id;
delete jsonData.product_id;
diff --git a/public/viewjs/productgroupform.js b/public/viewjs/productgroupform.js
index 87523eb9..e6d54352 100644
--- a/public/viewjs/productgroupform.js
+++ b/public/viewjs/productgroupform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("product-group-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/purchase.js b/public/viewjs/purchase.js
index 762c402b..63bf057a 100644
--- a/public/viewjs/purchase.js
+++ b/public/viewjs/purchase.js
@@ -4,6 +4,11 @@ $('#save-purchase-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("purchase-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/quantityunitconversionform.js b/public/viewjs/quantityunitconversionform.js
index 7f206d4b..85f1f847 100644
--- a/public/viewjs/quantityunitconversionform.js
+++ b/public/viewjs/quantityunitconversionform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("quconversion-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/quantityunitform.js b/public/viewjs/quantityunitform.js
index f61a4ebf..14db0978 100644
--- a/public/viewjs/quantityunitform.js
+++ b/public/viewjs/quantityunitform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("quantityunit-form", true))
+ {
+ return;
+ }
+
var jsonData = $('#quantityunit-form').serializeJSON();
Grocy.FrontendHelpers.BeginUiBusy("quantityunit-form");
diff --git a/public/viewjs/recipeform.js b/public/viewjs/recipeform.js
index 775410b9..33f057ec 100644
--- a/public/viewjs/recipeform.js
+++ b/public/viewjs/recipeform.js
@@ -30,6 +30,11 @@ $('.save-recipe').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("recipe-form", true))
+ {
+ return;
+ }
+
var jsonData = $('#recipe-form').serializeJSON();
Grocy.FrontendHelpers.BeginUiBusy("recipe-form");
@@ -301,6 +306,11 @@ $('#save-recipe-include-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("recipe-include-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/recipeposform.js b/public/viewjs/recipeposform.js
index 70f66dd0..acec2007 100644
--- a/public/viewjs/recipeposform.js
+++ b/public/viewjs/recipeposform.js
@@ -4,6 +4,11 @@ $('#save-recipe-pos-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("recipe-pos-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/shoppinglistform.js b/public/viewjs/shoppinglistform.js
index 8792db90..8d7c5915 100644
--- a/public/viewjs/shoppinglistform.js
+++ b/public/viewjs/shoppinglistform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("shopping-list-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/shoppinglistitemform.js b/public/viewjs/shoppinglistitemform.js
index 3e5fcf64..fa444703 100644
--- a/public/viewjs/shoppinglistitemform.js
+++ b/public/viewjs/shoppinglistitemform.js
@@ -4,6 +4,11 @@ $('#save-shoppinglist-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("shoppinglist-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
@@ -284,7 +289,7 @@ eitherRequiredFields.on('input', function()
eitherRequiredFields.not(this).prop('required', !$(this).val().length);
Grocy.FrontendHelpers.ValidateForm('shoppinglist-form');
});
-
+eitherRequiredFields.trigger("input");
if (GetUriParam("product-name") != null)
{
diff --git a/public/viewjs/shoppinglocationform.js b/public/viewjs/shoppinglocationform.js
index 09e81cf2..16e90208 100644
--- a/public/viewjs/shoppinglocationform.js
+++ b/public/viewjs/shoppinglocationform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("shoppinglocation-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/stockentryform.js b/public/viewjs/stockentryform.js
index 62710970..51484574 100644
--- a/public/viewjs/stockentryform.js
+++ b/public/viewjs/stockentryform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("stockentry-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/taskcategoryform.js b/public/viewjs/taskcategoryform.js
index ae02241f..4ec20607 100644
--- a/public/viewjs/taskcategoryform.js
+++ b/public/viewjs/taskcategoryform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("task-category-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/taskform.js b/public/viewjs/taskform.js
index 298a586b..397fb1b3 100644
--- a/public/viewjs/taskform.js
+++ b/public/viewjs/taskform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("task-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/transfer.js b/public/viewjs/transfer.js
index 4ad149ee..a88838ac 100644
--- a/public/viewjs/transfer.js
+++ b/public/viewjs/transfer.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("transfer-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/userentityform.js b/public/viewjs/userentityform.js
index eac5ff67..a02cea61 100644
--- a/public/viewjs/userentityform.js
+++ b/public/viewjs/userentityform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("userentity-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/userfieldform.js b/public/viewjs/userfieldform.js
index 14d79a02..a7b89d38 100644
--- a/public/viewjs/userfieldform.js
+++ b/public/viewjs/userfieldform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("userfield-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/userform.js b/public/viewjs/userform.js
index ce348650..87c227a5 100644
--- a/public/viewjs/userform.js
+++ b/public/viewjs/userform.js
@@ -28,6 +28,11 @@ $('#save-user-button').on('click', function(e)
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("user-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/public/viewjs/userobjectform.js b/public/viewjs/userobjectform.js
index 4cb33321..ca42ddce 100644
--- a/public/viewjs/userobjectform.js
+++ b/public/viewjs/userobjectform.js
@@ -2,6 +2,11 @@
{
e.preventDefault();
+ if (!Grocy.FrontendHelpers.ValidateForm("userobject-form", true))
+ {
+ return;
+ }
+
if ($(".combobox-menu-visible").length)
{
return;
diff --git a/views/mealplan.blade.php b/views/mealplan.blade.php
index 8853f146..e0b49ef8 100644
--- a/views/mealplan.blade.php
+++ b/views/mealplan.blade.php
@@ -200,7 +200,6 @@
class="btn btn-secondary"
data-dismiss="modal">{{ $__t('Cancel') }}
@@ -251,7 +250,6 @@
class="btn btn-secondary"
data-dismiss="modal">{{ $__t('Cancel') }}
@@ -304,7 +302,6 @@
class="btn btn-secondary"
data-dismiss="modal">{{ $__t('Cancel') }}
@@ -343,7 +340,6 @@
class="btn btn-secondary"
data-dismiss="modal">{{ $__t('Cancel') }}
diff --git a/views/recipeform.blade.php b/views/recipeform.blade.php
index e20968e4..1a5e465f 100644
--- a/views/recipeform.blade.php
+++ b/views/recipeform.blade.php
@@ -405,7 +405,6 @@
class="btn btn-secondary"
data-dismiss="modal">{{ $__t('Cancel') }}