Skip to content
This repository has been archived by the owner on Apr 6, 2022. It is now read-only.

Commit

Permalink
Disable client-side validation on setRequiredIndicatorVisible() (#77)
Browse files Browse the repository at this point in the history
Fixes #4077
  • Loading branch information
Denis committed May 22, 2018
1 parent e010517 commit 31da851
Show file tree
Hide file tree
Showing 15 changed files with 481 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pom.xml
Expand Up @@ -60,7 +60,28 @@
<version>${flow.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.0.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webApp>
<resourceBases>
<resourceBase>${project.basedir}/src/main/resources/META-INF/resources</resourceBase>
</resourceBases>
</webApp>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>runTests</id>
Expand All @@ -71,6 +92,11 @@
<version>${flow.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
</dependencies>
</profile>
</profiles>
Expand Down
Expand Up @@ -21,6 +21,7 @@
import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.InputNotifier;
import com.vaadin.flow.component.KeyNotifier;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.data.value.HasValueChangeMode;
import com.vaadin.flow.data.value.ValueChangeMode;

Expand All @@ -36,6 +37,8 @@ public class PasswordField
HasAutocomplete, HasAutocapitalize, HasAutocorrect {
private ValueChangeMode currentMode;

private boolean isConnectorAttached;

/**
* Constructs an empty {@code PasswordField}.
*/
Expand Down Expand Up @@ -345,4 +348,16 @@ public void setRevealButtonVisible(boolean revealButtonVisible) {
public String getEmptyValue() {
return "";
}

@Override
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
super.setRequiredIndicatorVisible(requiredIndicatorVisible);
if (!isConnectorAttached) {
UI.getCurrent().getPage()
.addJavaScript("frontend://textConnector.js");
isConnectorAttached = true;
}
RequiredValidationUtil.updateClientValidation(requiredIndicatorVisible,
this);
}
}
@@ -0,0 +1,62 @@
/*
* Copyright 2000-2017 Vaadin Ltd.
*
* 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 com.vaadin.flow.component.textfield;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.internal.StateNode;

/**
* Utility class for text field mixin web components to disable/enable client
* side validation.
*
* @author Vaadin Ltd
*
*/
final class RequiredValidationUtil {

RequiredValidationUtil() {
// utility class should not be instantiated
}

static void updateClientValidation(boolean requiredIndicatorVisible,
Component component) {
if (requiredIndicatorVisible) {
disableClientValiation(component);
} else {
enableClientValiation(component);
}
}

static void disableClientValiation(Component component) {
execJS(component,
"window.Vaadin.Flow.textConnector.disableClientValidation($0);");
}

static void enableClientValiation(Component component) {
execJS(component,
"window.Vaadin.Flow.textConnector.enableClientValidation($0);");
}

private static void execJS(Component component, String js) {
StateNode node = component.getElement().getNode();

node.runWhenAttached(ui -> ui.getInternals().getStateTree()
.beforeClientResponse(node, context -> ui.getPage()
.executeJavaScript(js, component.getElement())));

}

}
15 changes: 15 additions & 0 deletions src/main/java/com/vaadin/flow/component/textfield/TextArea.java
Expand Up @@ -20,6 +20,7 @@
import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.InputNotifier;
import com.vaadin.flow.component.KeyNotifier;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.data.value.HasValueChangeMode;
import com.vaadin.flow.data.value.ValueChangeMode;

Expand All @@ -34,6 +35,8 @@ public class TextArea extends GeneratedVaadinTextArea<TextArea, String>
HasAutocomplete, HasAutocapitalize, HasAutocorrect {
private ValueChangeMode currentMode;

private boolean isConnectorAttached;

/**
* Constructs an empty {@code TextArea}.
*/
Expand Down Expand Up @@ -294,4 +297,16 @@ public void setPreventInvalidInput(boolean preventInvalidInput) {
public String getEmptyValue() {
return "";
}

@Override
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
super.setRequiredIndicatorVisible(requiredIndicatorVisible);
if (!isConnectorAttached) {
UI.getCurrent().getPage()
.addJavaScript("frontend://textConnector.js");
isConnectorAttached = true;
}
RequiredValidationUtil.updateClientValidation(requiredIndicatorVisible,
this);
}
}
15 changes: 15 additions & 0 deletions src/main/java/com/vaadin/flow/component/textfield/TextField.java
Expand Up @@ -20,6 +20,7 @@
import com.vaadin.flow.component.HasValidation;
import com.vaadin.flow.component.InputNotifier;
import com.vaadin.flow.component.KeyNotifier;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.data.value.HasValueChangeMode;
import com.vaadin.flow.data.value.ValueChangeMode;

Expand All @@ -34,6 +35,8 @@ public class TextField extends GeneratedVaadinTextField<TextField, String>
HasAutocomplete, HasAutocapitalize, HasAutocorrect {
private ValueChangeMode currentMode;

private boolean isConnectorAttached;

/**
* Constructs an empty {@code TextField}.
*/
Expand Down Expand Up @@ -333,4 +336,16 @@ public void setTitle(String title) {
public String getEmptyValue() {
return "";
}

@Override
public void setRequiredIndicatorVisible(boolean requiredIndicatorVisible) {
super.setRequiredIndicatorVisible(requiredIndicatorVisible);
if (!isConnectorAttached) {
UI.getCurrent().getPage()
.addJavaScript("frontend://textConnector.js");
isConnectorAttached = true;
}
RequiredValidationUtil.updateClientValidation(requiredIndicatorVisible,
this);
}
}
17 changes: 17 additions & 0 deletions src/main/resources/META-INF/resources/frontend/textConnector.js
@@ -0,0 +1,17 @@
window.Vaadin.Flow.textConnector = {

disableClientValidation: function (textComponent){
if ( typeof textComponent.$validation == 'undefined'){
textComponent.$validation = textComponent.checkValidity;
textComponent.checkValidity = function() { return true; };
}
},

enableClientValidation: function (textComponent){
if ( textComponent.$validation ){
textComponent.checkValidity = textComponent.$validation;
delete textComponent.$validation;
}
}

}
@@ -0,0 +1,44 @@
/*
* Copyright 2000-2017 Vaadin Ltd.
*
* 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 com.vaadin.flow.component.textfield.tests;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Keys;
import org.openqa.selenium.WebElement;

import com.vaadin.flow.testutil.AbstractComponentIT;

public abstract class AbstractRequiredValidationIT extends AbstractComponentIT {

@Test
public void requiredValidation_disabledWithBinder_enabledViaExpicitCall()
throws InterruptedException {
open();

WebElement name = findElement(By.id("name"));
name.sendKeys(Keys.TAB);
Assert.assertFalse(Boolean.parseBoolean(name.getAttribute("invalid")));

findElement(By.id("hide")).click();

name.sendKeys(Keys.TAB);

Assert.assertTrue(Boolean.parseBoolean(name.getAttribute("invalid")));
}

}
@@ -0,0 +1,55 @@
/*
* Copyright 2000-2017 Vaadin Ltd.
*
* 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 com.vaadin.flow.component.textfield.tests;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.NativeButton;
import com.vaadin.flow.data.binder.BeanValidationBinder;

public abstract class AbstractRequiredValidationPage<T extends HasValue<?, ?>>
extends Div {

public AbstractRequiredValidationPage() {
T name = createTextField();

Entity entity = new Entity();
BeanValidationBinder<Entity> binder = new BeanValidationBinder<>(
Entity.class);
binder.forField((HasValue<?, ?>) name).bind("name");

Component nameComponent = (Component) name;

nameComponent.setId("name");

binder.setBean(entity);

add(nameComponent);

NativeButton off = new NativeButton(
"Make required indicator invisible and set requied", event -> {
name.setRequiredIndicatorVisible(false);
setRequired(name);
});
off.setId("hide");
add(off);
}

protected abstract void setRequired(T field);

protected abstract T createTextField();
}
@@ -0,0 +1,38 @@
/*
* Copyright 2000-2017 Vaadin Ltd.
*
* 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 com.vaadin.flow.component.textfield.tests;

import javax.validation.constraints.NotNull;

public class Entity {

@NotNull
private String name;

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

@Override
public String toString() {
return "Entity, name: " + name;
}

}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2017 Vaadin Ltd.
*
* 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 com.vaadin.flow.component.textfield.tests;

import com.vaadin.flow.testutil.TestPath;

/**
* The test code is in the super class.
*
* @author Vaadin Ltd
*
*/
@TestPath("password-field-required-binder")
public class PasswordFieldRequiredValidationIT
extends AbstractRequiredValidationIT {

}

0 comments on commit 31da851

Please sign in to comment.