Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(forms): handle standalone <form> tag in NgControlStatusGroup directive correctly #40344

Closed
wants to merge 2 commits into from

Conversation

AndrewKushnir
Copy link
Contributor

The NgControlStatusGroup directive is shared between template-driven and reactive form modules. In cases when
only reactive forms module is present, the NgControlStatusGroup directive is still activated on all <form>
elements, but if there is no other reactive directive applied (such as formGroup), corresponding ControlContainer
token is missing, thus causing exceptions (since NgControlStatusGroup directive relies on it to determine the
status). This commit updates the logic to handle the case when no ControlContainer is present (effectively making
directive logic a noop in this case).

Alternative approach (more risky) worth considering in the future is to split the NgControlStatusGroup into
2 directives with different set of selectors and include them into template-driven and reactive modules separately.
The downside is that these directives might be activated simultaneously on the same element (e.g. <form>),
effectively doing the work twice.

Resolves #38391.

PR Type

What kind of change does this PR introduce?

  • Bugfix

Does this PR introduce a breaking change?

  • Yes
  • No

…tusGroup` directive

The `NgControlStatusGroup` directive is shared between template-driven and reactive form modules. In cases when
only reactive forms module is present, the `NgControlStatusGroup` directive is still activated on all `<form>`
elements, but if there is no other reactive directive applied (such as `formGroup`), corresponding `ControlContainer`
token is missing, thus causing exceptions (since `NgControlStatusGroup` directive relies on it to determine the
status). This commit updates the logic to handle the case when no `ControlContainer` is present (effectively making
directive logic a noop in this case).

Alternative approach (more risky) worth considering in the future is to split the `NgControlStatusGroup` into
2 directives with different set of selectors and include them into template-driven and reactive modules separately.
The downside is that these directives might be activated simultaneously on the same element (e.g. `<form>`),
effectively doing the work twice.

Resolves angular#38391.
@ngbot ngbot bot modified the milestone: Backlog Jan 7, 2021
@google-cla google-cla bot added the cla: yes label Jan 7, 2021
@AndrewKushnir AndrewKushnir changed the title fix(forms): handle standalone <form> tag correctly in NgControlStatusGroup directive fix(forms): handle standalone <form> tag in NgControlStatusGroup directive correctly Jan 7, 2021
this._cd = cd;
}

get ngClassUntouched(): boolean {
return this._cd.control ? this._cd.control.untouched : false;
return this._cd?.control ? this._cd.control.untouched : false;
Copy link
Member

Choose a reason for hiding this comment

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

Could this be:

Suggested change
return this._cd?.control ? this._cd.control.untouched : false;
return this._cd?.control?.untouched ?? false;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great idea (I've updated the change), thanks @petebacondarwin! 👍

I was also thinking to refactor that code in the followup PR to get rid of duplicate getters.

Current code:

export const ngControlStatusHost = {
  '[class.ng-untouched]': 'ngClassUntouched',
  '[class.ng-touched]': 'ngClassTouched',
  ...

How it may look like:

export const ngControlStatusHost = {
  '[class.ng-untouched]': 'is("untouched")',
  '[class.ng-touched]': 'is("touched")',
  ...
};

and also a new is function:

  is(status: string): boolean {
    return this._cd?.control?.[status] ?? false;
  }

What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah I like that.

Copy link

@dev054 dev054 Jan 7, 2021

Choose a reason for hiding this comment

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

Sorry for the intrusion but why not get rid of null coalescing and do it like this:

  is(status: string): boolean {
    // or Boolean(...)
    return !!this._cd?.control?.[status];
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@dev054, agree, we can do that too.

@AndrewKushnir AndrewKushnir marked this pull request as ready for review January 7, 2021 20:46
@AndrewKushnir AndrewKushnir added action: review The PR is still awaiting reviews from at least one requested reviewer and removed state: WIP labels Jan 7, 2021
@AndrewKushnir AndrewKushnir added action: presubmit The PR is in need of a google3 presubmit and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jan 7, 2021
@AndrewKushnir
Copy link
Contributor Author

Presubmit.

@AndrewKushnir AndrewKushnir added target: patch This PR is targeted for the next patch release action: merge The PR is ready for merge by the caretaker and removed action: presubmit The PR is in need of a google3 presubmit labels Jan 8, 2021
@atscott atscott closed this in fdbd3ca Jan 8, 2021
atscott pushed a commit that referenced this pull request Jan 8, 2021
…tusGroup` directive (#40344)

The `NgControlStatusGroup` directive is shared between template-driven and reactive form modules. In cases when
only reactive forms module is present, the `NgControlStatusGroup` directive is still activated on all `<form>`
elements, but if there is no other reactive directive applied (such as `formGroup`), corresponding `ControlContainer`
token is missing, thus causing exceptions (since `NgControlStatusGroup` directive relies on it to determine the
status). This commit updates the logic to handle the case when no `ControlContainer` is present (effectively making
directive logic a noop in this case).

Alternative approach (more risky) worth considering in the future is to split the `NgControlStatusGroup` into
2 directives with different set of selectors and include them into template-driven and reactive modules separately.
The downside is that these directives might be activated simultaneously on the same element (e.g. `<form>`),
effectively doing the work twice.

Resolves #38391.

PR Close #40344
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Feb 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker area: forms cla: yes target: patch This PR is targeted for the next patch release type: bug/fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Can't use a <form> tag with a [formControl] directive
3 participants