Skip to content

Conversation

@chrissainty
Copy link
Contributor

@chrissainty chrissainty commented Jul 16, 2020

  • Modified the EditContext parameter to return _fixedEditContext
  • Introduced a new field, _providedEditContext which stores any EditContext provided by the developer. This means we don't break existing functionality.
  • Updates to OnParametersSet to use the new _providedEditContext field instead of the EditContext property
  • Unit tests to cover new EditForm functionality

@SteveSandersonMS tagged for review

Addresses #12238
Addresses #23354

…ameter. Also added some tests to cover the new functionality
@chrissainty chrissainty requested review from a team and SteveSandersonMS as code owners July 16, 2020 13:49
@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Jul 16, 2020
private readonly Func<Task> _handleSubmitDelegate; // Cache to avoid per-render allocations

private EditContext? _fixedEditContext;
private EditContext? _providedEditContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with this area, do we need the extra field? Or can we make _providedContext hold the right value whether it received a Model or a Context

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _providedEditContext field is there to track if the EditContext was provided directly via the EditContext parameter. This mean we don't break the current functionality in the OnParametersSet method which checks if the developer has provided a value for both EditContext and Model.


namespace Microsoft.AspNetCore.Components.Forms
{
public class EditFormTest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I hope the tests are ok, its my first go at writing them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests are looking great. Good stuff!

Comment on lines 41 to 45
public EditContext? EditContext
{
get => _fixedEditContext;
set => _providedEditContext = value;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this risks being a little weird, because I know we don't recommend people write to parameter properties directly, but if someone does this will be kind of bizarre. If you write a value to this property then try to read it back, you'll get a totally different value :)

Would it be possible instead to do something like:

bool _hasSetEditContextExplicitly;

[Parameter]
public EditContext? EditContext
{
    get => _fixedEditContext;
    set
    {
        _fixedEditContext = value;
        _hasSetEditContextExplicitly = true;
    }
}

... and then inside OnParametersSet:

if (_hasSetEditContextExplicitly && Model != null)
{
    throw "Don't set both"
}
else if (EditContext == null && Model == null)
{
   throw "Set at least one"
}

Sorry for not noticing this earlier on the original proposal!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is why I can't be left alone to review things after lunch 😄

Copy link
Contributor Author

@chrissainty chrissainty Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense, I'll make the change

var returnedEditContext = editFormComponent.EditContext;

// Assert
Assert.NotNull(returnedEditContext);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Assert.NotNull(returnedEditContext);
Assert.Same(editContext, returnedEditContext);

@javiercn
Copy link
Member

This is a patch with the changes in the ref assembly, it's not an API change, but the tool is complaining, so we just need to apply that to keep the build happy
Update-ref-assemblies.txt

@pranavkm pranavkm changed the base branch from master to release/5.0-preview8 July 16, 2020 15:47
@pranavkm pranavkm requested a review from dougbu as a code owner July 16, 2020 15:47
@pranavkm pranavkm changed the base branch from release/5.0-preview8 to master July 16, 2020 15:47
@chrissainty
Copy link
Contributor Author

@javiercn Is that patch something I need to do? If so what do I need to do? :)

get => _fixedEditContext;
set
{
if (value != null)
Copy link
Contributor Author

@chrissainty chrissainty Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this was the right thing to do now I'm looking at it here. This would mean that once an EditContext has been set it can't be set back to null. Is that a scenario that should be catered for?

@SteveSandersonMS @javiercn

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's never going to be, is it? even if you set a model, wouldn't that be the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't think of a reasonable scenario where you would pass in an EditContext and then later decide to set it to null. But just wanted to check

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same feeling, but @SteveSandersonMS is the expert on this area, so I would defer the final say to him

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want a null check, could you throw ArgumentNullException? I think we shouldn't ignore the null value. Either accept it, or throw :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Of these options, I'd prefer throwing, since there's no real value in letting people set it back to null)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this check so that _hasSetEditContextExplicity doesn't get set to true when the value is null. Perhaps I should adjust the code to this:

public EditContext? EditContext
{
    get => _fixedEditContext;
    set
    {
        _fixedEditContext = value;
        _hasSetEditContextExplicity = value != null ? true : false;
    }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like that would work to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I've push the update

@javiercn
Copy link
Member

@chrissainty you can apply the patch manually (just download it and apply the changes) if you know how, or if you do it the "manual way" inspect the patch, open the file and replace the line manually.

This is part of how we generate reference assemblies for compilation and sometimes it causes this issues. We are working on making this happen automagically I believe

throw new InvalidOperationException($"{nameof(EditForm)} requires a {nameof(Model)} " +
$"parameter, or an {nameof(EditContext)} parameter, but not both.");
}
else if (EditContext == null && Model == null)
Copy link
Member

@SteveSandersonMS SteveSandersonMS Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this now be else if (!_hasSetEditContextExplicitly && Model == null) ?

Because the rule is: you must supply a model if and only if you didn't supply an edit context.

In the event where you:

  • First supplied a non-null model
  • Then on the next render supplied a null model

Then we'd want to throw I think, but the existing logic wouldn't.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, agreed. I'll update it.

// Update _fixedEditContext if we don't have one yet, or if they are supplying a
// potentially new EditContext, or if they are supplying a different Model
if (_fixedEditContext == null || EditContext != null || Model != _fixedEditContext.Model)
if (_fixedEditContext == null || (!_hasSetEditContextExplicitly && Model != _fixedEditContext.Model))
Copy link
Member

@SteveSandersonMS SteveSandersonMS Jul 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I think this could be simplified to:

Suggested change
if (_fixedEditContext == null || (!_hasSetEditContextExplicitly && Model != _fixedEditContext.Model))
if (!_hasSetEditContextExplicitly && Model != _fixedEditContext?.Model)

... because if _hasSetEditContextExplicitly then we know _fixedEditContext != null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also the comment above it is slightly out of date now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strictly speaking the check could be expressed as:

if (Model != null && Model != _fixedEditContext?.Model)

(because we know that if Model != null, then _hasSetEditContextExplicitly is false otherwise we would already have thrown above)

Arguably this is a more natural phrasing because it's just stating that if you give us any new model, we want to use it.

@SteveSandersonMS
Copy link
Member

Thanks very much for the updates, @chrissainty! I think this is really close to being done now.

One final thought: the name _fixedEditContext no longer really makes sense, and we could simplify it just to being called _editContext now. It's simply the backing field for the EditContext property now. If you feel like making this rename then great, but if not that's absolutely fine and we won't hold up the PR on it :)

@chrissainty
Copy link
Contributor Author

Give me 2 minutes @SteveSandersonMS, I'll get it done! :)

@SteveSandersonMS
Copy link
Member

Awesome, thanks!

@captainsafia @pranavkm Can I leave it with one of you to merge when the tests pass and if you're happy with it? Up to you whether you also want to ask for/wait for this update too.

@chrissainty
Copy link
Contributor Author

@SteveSandersonMS @captainsafia @pranavkm I've addressed the last comment, all should be good now :)

@captainsafia
Copy link
Member

@SteveSandersonMS @captainsafia @pranavkm I've addressed the last comment, all should be good now :)

Thanks, Chris! Taking a look now.

Copy link
Member

@captainsafia captainsafia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like all the feedback has ben addressed here. Thanks for adding the tests!

Copy link
Member

@SteveSandersonMS SteveSandersonMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brilliant. Thanks @chrissainty!

@chrissainty
Copy link
Contributor Author

My pleasure! This first sprint has been awesome, I hope we can do it again, soon 😀

@mkArtakMSFT mkArtakMSFT added the community-contribution Indicates that the PR has been added by a community member label Jul 16, 2020
@captainsafia captainsafia merged commit 7132792 into dotnet:master Jul 17, 2020
@captainsafia
Copy link
Member

@chrissainty Thank you for the contribution! Your pull request has been merged!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants