Beispiel #1
0
        public async Task SuppliesFieldClassCorrespondingToFieldState()
        {
            // Arrange
            var model         = new TestModel();
            var rootComponent = new TestInputHostComponent <string, TestInputComponent <string> >
            {
                EditContext     = new EditContext(model),
                ValueExpression = () => model.StringProperty
            };
            var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty);

            // Act/Assert: Initally, it's valid and unmodified
            var inputComponent = await RenderAndGetTestInputComponentAsync(rootComponent);

            Assert.Equal("valid", inputComponent.FieldClass);
            Assert.Equal("valid", inputComponent.CssClass); // Same because no Class was specified

            // Act/Assert: Modify the field
            rootComponent.EditContext.NotifyFieldChanged(fieldIdentifier);
            Assert.Equal("modified valid", inputComponent.FieldClass);
            Assert.Equal("modified valid", inputComponent.CssClass);

            // Act/Assert: Make it invalid
            var messages = new ValidationMessageStore(rootComponent.EditContext);

            messages.Add(fieldIdentifier, "I do not like this value");
            Assert.Equal("modified invalid", inputComponent.FieldClass);
            Assert.Equal("modified invalid", inputComponent.CssClass);

            // Act/Assert: Clear the modification flag
            rootComponent.EditContext.MarkAsUnmodified(fieldIdentifier);
            Assert.Equal("invalid", inputComponent.FieldClass);
            Assert.Equal("invalid", inputComponent.CssClass);

            // Act/Assert: Make it valid
            messages.Clear();
            Assert.Equal("valid", inputComponent.FieldClass);
            Assert.Equal("valid", inputComponent.CssClass);
        }
        public void RequestsValidationWhenValidateIsCalled()
        {
            // Arrange
            var editContext = new EditContext(new object());
            var messages    = new ValidationMessageStore(editContext);

            editContext.OnValidationRequested += (sender, eventArgs) =>
            {
                Assert.Same(editContext, sender);
                Assert.NotNull(eventArgs);
                messages.Add(
                    new FieldIdentifier(new object(), "some field"),
                    "Some message");
            };

            // Act
            var isValid = editContext.Validate();

            // assert
            Assert.False(isValid);
            Assert.Equal(new[] { "Some message" }, editContext.GetValidationMessages());
        }
Beispiel #3
0
        public async Task AriaAttributeRemovedWhenStateChangesToValidFromInvalid()
        {
            // Arrange
            var model         = new TestModel();
            var rootComponent = new TestInputHostComponent <string, TestInputComponent <string> >
            {
                EditContext     = new EditContext(model),
                ValueExpression = () => model.StringProperty
            };
            var fieldIdentifier = FieldIdentifier.Create(() => model.StringProperty);
            var renderer        = new TestRenderer();
            var messageStore    = new ValidationMessageStore(rootComponent.EditContext);

            messageStore.Add(fieldIdentifier, "Artificial error message");
            var rootComponentId = renderer.AssignRootComponentId(rootComponent);
            await renderer.RenderRootComponentAsync(rootComponentId);

            // Initally, it rendered one batch and is invalid
            var batch1           = renderer.Batches.Single();
            var componentFrame1  = batch1.GetComponentFrames <TestInputComponent <string> >().Single();
            var inputComponentId = componentFrame1.ComponentId;
            var component        = (TestInputComponent <string>)componentFrame1.Component;

            Assert.Equal("invalid", component.CssClass);
            Assert.NotNull(component.AdditionalAttributes);
            Assert.True(component.AdditionalAttributes.ContainsKey("aria-invalid"));

            // Act: update the field state in the EditContext and notify
            messageStore.Clear(fieldIdentifier);
            await renderer.Dispatcher.InvokeAsync(rootComponent.EditContext.NotifyValidationStateChanged);

            // Assert: The input component rendered itself again and now has the new class
            var batch2 = renderer.Batches.Skip(1).Single();

            Assert.Equal(inputComponentId, batch2.DiffsByComponentId.Keys.Single());
            Assert.Equal("valid", component.CssClass);
            Assert.Null(component.AdditionalAttributes);
        }
        /// <summary>
        /// Validate the whole form and trigger client UI update.
        /// </summary>
        /// <param name="editContext"></param>
        /// <param name="messages"></param>
        private async void ValidateModel(EditContext editContext, ValidationMessageStore messages)
        {
            // <EditForm> should now be able to run async validations:
            // https://github.com/dotnet/aspnetcore/issues/11914
            var validationResults = await TryValidateModel(editContext);

            messages.Clear();

            var graph = new ModelGraphCache(editContext.Model);

            foreach (var error in validationResults.Errors)
            {
                var(propertyValue, propertyName) = graph.EvalObjectProperty(error.PropertyName);
                // while it is impossible to have a validation error for a null child property, better be safe than sorry...
                if (propertyValue != null)
                {
                    var fieldID = new FieldIdentifier(propertyValue, propertyName);
                    messages.Add(fieldID, error.ErrorMessage);
                }
            }

            editContext.NotifyValidationStateChanged();
        }
Beispiel #5
0
        /// <summary>
        /// Validate the whole form and trigger client UI update.
        /// </summary>
        /// <param name="editContext"></param>
        /// <param name="messages"></param>
        private void ValidateModel(EditContext editContext, ValidationMessageStore messages)
        {
            // WARNING: DO NOT USE Async Void + ValidateAsync here
            // Explanation: Blazor UI will get VERY BUGGY for some reason if you do that. (Field CSS lagged behind validation)
            var validationResults = TryValidateModel(editContext);

            messages.Clear();

            var graph = new ModelGraphCache(editContext.Model);

            foreach (var error in validationResults.Errors)
            {
                var(propertyValue, propertyName) = graph.EvalObjectProperty(error.PropertyName);
                // while it is impossible to have a validation error for a null child property, better be safe than sorry...
                if (propertyValue != null)
                {
                    var fieldID = new FieldIdentifier(propertyValue, propertyName);
                    messages.Add(fieldID, error.ErrorMessage);
                }
            }

            editContext.NotifyValidationStateChanged();
        }
Beispiel #6
0
 /// <summary>
 /// Adds a validation message for the specified field.
 /// </summary>
 /// <param name="store">The <see cref="ValidationMessageStore"/>.</param>
 /// <param name="accessor">Identifies the field for which to add the message.</param>
 /// <param name="message">The validation message.</param>
 public static void Add(this ValidationMessageStore store, Expression <Func <object> > accessor, string message)
 => store.Add(FieldIdentifier.Create(accessor), message);