You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2015/01/05 21:42:47 UTC
tapestry-5 git commit: TAP5-2391: Properly track Fields in
ValidationTracker, even during Ajax requests
Repository: tapestry-5
Updated Branches:
refs/heads/master fa691e262 -> 280940fb0
TAP5-2391: Properly track Fields in ValidationTracker, even during Ajax requests
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/280940fb
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/280940fb
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/280940fb
Branch: refs/heads/master
Commit: 280940fb098a4766effe297c20812042723529a8
Parents: fa691e2
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Mon Jan 5 12:42:39 2015 -0800
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Mon Jan 5 12:42:39 2015 -0800
----------------------------------------------------------------------
.../main/java/org/apache/tapestry5/Field.java | 5 +--
.../main/java/org/apache/tapestry5/Field2.java | 38 ++++++++++++++++++++
.../apache/tapestry5/ValidationTrackerImpl.java | 26 +++++++++-----
.../tapestry5/corelib/base/AbstractField.java | 16 ++++++++-
.../integration/app1/AjaxGroovyTests.groovy | 12 +++++++
5 files changed, 86 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/280940fb/tapestry-core/src/main/java/org/apache/tapestry5/Field.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/Field.java b/tapestry-core/src/main/java/org/apache/tapestry5/Field.java
index eabc532..c22b28d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/Field.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/Field.java
@@ -1,5 +1,3 @@
-// Copyright 2013 The Apache Software Foundation
-//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -22,6 +20,9 @@ package org.apache.tapestry5;
* component's {@link #getControlName()} will only be accurate after it has rendered. In some cases, when generating
* JavaScript for example, it is necessary to {@linkplain org.apache.tapestry5.services.Heartbeat#defer(Runnable) wait
* until the end of the current Heartbeat} to ensure that all components have had their chance to render.
+ * <p/>
+ * Most Fields also implement {@link org.apache.tapestry5.Field2}, which was introduced to bridge a gap related to
+ * re-rendering a form as part of an Ajax request.
*/
public interface Field extends ClientElement
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/280940fb/tapestry-core/src/main/java/org/apache/tapestry5/Field2.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/Field2.java b/tapestry-core/src/main/java/org/apache/tapestry5/Field2.java
new file mode 100644
index 0000000..3322325
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/Field2.java
@@ -0,0 +1,38 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5;
+
+/**
+ * Due to how control names and client ids are allocated inside during an Ajax request, it is difficult to
+ * to connect input data and field validation errors to the fields, since the control name and client id are different
+ * during the processing of the submitted form data and during the subsequent render. Starting in 5.4, the
+ * key used to identify a field inside the {@link org.apache.tapestry5.ValidationTracker is this new validation id,
+ * which is assigned on first read.
+ * <p/>
+ * If a field inplements {@link org.apache.tapestry5.Field} but not Field2, then the control name is used as the
+ * validation id (which will work correctly during non-Ajax requests).
+ * <p/>
+ * This assumes a "flat" field structure, where a given component renders only once (not multiple times, inside
+ * a {@link org.apache.tapestry5.corelib.components.Loop}.
+ *
+ * @since 5.4
+ */
+public interface Field2 extends Field
+{
+ /**
+ * Returns a request-scoped unique validation id for the field. This returns the same value regardless of how
+ * many times the field is rendered, which means that the behavior will be incorrect when the
+ * field component is placed inside a loop.
+ */
+ String getValidationId();
+}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/280940fb/tapestry-core/src/main/java/org/apache/tapestry5/ValidationTrackerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/ValidationTrackerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/ValidationTrackerImpl.java
index 33666a4..c77e154 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/ValidationTrackerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/ValidationTrackerImpl.java
@@ -1,5 +1,3 @@
-// Copyright 2006-2013 The Apache Software Foundation
-//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
@@ -35,15 +33,15 @@ public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedOb
{
private static final long serialVersionUID = -3653306147088451811L;
- private final String fieldName;
+ private final String validationId;
private String input;
private String errorMessage;
- FieldTracker(String fieldName)
+ FieldTracker(String validationId)
{
- this.fieldName = fieldName;
+ this.validationId = validationId;
}
}
@@ -52,6 +50,7 @@ public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedOb
private List<FieldTracker> fieldTrackers;
// Rebuilt on-demand
+ // Keyed on validationId
private transient Map<String, FieldTracker> fieldToTracker;
@@ -66,12 +65,23 @@ public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedOb
fieldToTracker = CollectionFactory.newMap();
for (FieldTracker ft : fieldTrackers)
- fieldToTracker.put(ft.fieldName, ft);
+ fieldToTracker.put(ft.validationId, ft);
+ }
+
+ private String getKey(Field field)
+ {
+ if (field instanceof Field2)
+ {
+ Field2 field2 = (Field2) field;
+ return field2.getValidationId();
+ }
+
+ return field.getControlName();
}
private FieldTracker get(Field field)
{
- String key = field.getControlName();
+ String key = getKey(field);
refreshFieldToTracker();
@@ -90,7 +100,7 @@ public final class ValidationTrackerImpl extends BaseOptimizedSessionPersistedOb
refreshFieldToTracker();
- String key = fieldTracker.fieldName;
+ String key = fieldTracker.validationId;
if (!fieldToTracker.containsKey(key))
{
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/280940fb/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
index eec94df..851de73 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/base/AbstractField.java
@@ -30,6 +30,7 @@ import org.apache.tapestry5.services.Request;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import java.io.Serializable;
+import java.util.UUID;
/**
* Provides initialization of the clientId and elementName properties. In addition, adds the {@link RenderInformals},
@@ -38,7 +39,7 @@ import java.io.Serializable;
* @tapestrydoc
*/
@SupportsInformalParameters
-public abstract class AbstractField implements Field
+public abstract class AbstractField implements Field2
{
/**
* The user presentable label for the field. If not provided, a reasonable label is generated from the component's
@@ -362,4 +363,17 @@ public abstract class AbstractField implements Field
beanValidationContext.setCurrentProperty(null);
}
+
+ private String validationId;
+
+ @Override
+ public String getValidationId()
+ {
+ if (validationId == null)
+ {
+ validationId = UUID.randomUUID().toString();
+ }
+
+ return validationId;
+ }
}
http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/280940fb/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/AjaxGroovyTests.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/AjaxGroovyTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/AjaxGroovyTests.groovy
index 025db6b..b4531da 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/AjaxGroovyTests.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app1/AjaxGroovyTests.groovy
@@ -45,4 +45,16 @@ class AjaxGroovyTests extends App1TestCase {
assertText "css=#target > p", "You submitted the form."
}
+ @Test
+ void ajax_form_validation() {
+ openLinks "Ajax Validation"
+
+ click SUBMIT
+
+ waitForAjaxRequestsToComplete()
+
+ assertText "css=.form-group.has-error .help-block", "Server-side validation error."
+
+ }
+
}