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

Fixed null-safety issues #30

Merged

Conversation

dukefirehawk
Copy link
Collaborator

  1. Changed parameters of component constructor with @Attribute annotation to be nullable
  2. Fixed onPush issue
  3. Fixed null-safety issues in galleries

@GZGavinZhao
Copy link

Does it build? On my computer it doesn't.

Dart SDK version: 2.14.4 (stable) (Wed Oct 13 11:11:32 2021 +0200) on "linux_x64"

@dukefirehawk
Copy link
Collaborator Author

Hold on first. I need to check in a a few more null-safety fixed to clear away those errors.

@GZGavinZhao GZGavinZhao added the null safety Related to null safety migration label Oct 20, 2021
@GZGavinZhao
Copy link

GZGavinZhao commented Oct 21, 2021

@dukefirehawk No problem! Tell me when you're ready. I will push the Sass fix tonight.Done, no Sass warnings should produce now.

@lejard-h
Copy link
Collaborator

Next time can we address issues one by one in multiple PR.

Reviewing such PR is very hard.

For OnPush issue, we don't know if just changing the change detection strategy is engouh, maybe we need to call markForCheck() sometimes.

Copy link
Collaborator

@lejard-h lejard-h left a comment

Choose a reason for hiding this comment

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

Is it an automated null safety migration ?

I see a lot of @Input being nullable for no obvious reason.

Also is @Inject() annotation is not able to get Type anymore ? Why some types has been replaced by Object ?

@@ -231,8 +231,8 @@ class AutoFocusDirective extends RootFocusable implements OnInit, OnDestroy {
/// This value should not change during the component's life.
// TODO(google): Change to an attribute.
@Input()
set autoFocus(bool value) {
_autoFocus = value;
set autoFocus(bool? value) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe we could force it to be non null first. so we don't need to check for nullability and set it to false

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

None nullable fields need to be initialized. They are automatically converted during migration. Agree that it is not a good choice but then most if not all components need to have their fields initialized by going non nullable.

@@ -31,8 +30,11 @@ export 'package:angular_components/src/laminate/overlay/render/overlay_dom_rende
/// already.
/// A hidden focusable element is inserted before and after the overlay
/// container to support a11y features.
HtmlElement createAcxOverlayContainer(HtmlElement parent,
HtmlElement createAcxOverlayContainer(Object parent,
Copy link
Collaborator

Choose a reason for hiding this comment

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

why not keeping HtmlElement here ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

There are dependency across the codebase. Fixing one issue often trigger a chain reaction. The change to Object due to generated code in template.dart does not compile with HtmlElement.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably because of this #36

@Inject(overlayContainerParent) HtmlElement parent,
@Optional() @SkipSelf() @Inject(overlayContainerToken) container) {
if (container != null) return container;
@Inject(overlayContainerName) Object name,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here, using Object is strange. You also cast it after

@Optional()
@SkipSelf()
@Inject(overlayContainerName)
Object? containerName) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

String?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Template.dart will fail to compile complaining String? is not Object?

@@ -55,39 +55,40 @@ class ButtonDirective extends RootFocusable

/// String value to be passed to aria-disabled.
@HostBinding('attr.aria-disabled')
String get disabledStr => '$disabled';
String? get disabledStr => '$disabled';
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see why it can be nullable, we always return a String

Copy link
Collaborator Author

@dukefirehawk dukefirehawk Oct 25, 2021

Choose a reason for hiding this comment

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

@lejard-h @GZGavinZhao Not much time to get back for the past few days. The bulk of these changes are done to address issues flagged up in the gallery examples build stage. I will share some of the findings and the fixes that are put in.

  1. Issue The argument type 'Object' can't be assigned to the parameter type xxx #36 @lejard-h fix is a better way.
  2. Contructor marked as @optional must be nullable. Change to use nullable type. Need to make changes from parent class all way to the base abstract class.
  3. Constructor not marked with @optional must be non nullable. Similar to 3 above.
  4. Most of the components including class have fields declared without initialization. Add initializer wherever possible. Field holding function with generic type is problematic. Either late or make it nullable.
  5. Some factory class explicitly returns null. Return a custom empty class or throw ArguemetError.
  6. Some fields are explicitly set to null to clear the conditions or status. Remove set to null.
  7. Logic with List, Map or Iterable null checking in the code. Change to isEmpty check. Default List and Iterable to [] and map to {}
  8. Updating dom only accepts string type. This is an odd one. Will share the details once i nailed the flow down.
  9. @input fail when type in non nullable. Make it nullable on case by case basis. This one usually need to be relooked at. @lejard-h has pointed out some of these.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@lejard-h @GZGavinZhao Take this case for example, the generated code in .template.dart file for @HostbBinding is

    final currVal_2 = this.instance.disabledStr;
    if (import4.checkBinding(this._expr_2, currVal_2, null, null)) {
      import5.updateAttribute(el, 'aria-disabled', currVal_2);
      this._expr_2 = currVal_2;
    }

It is calling dom_helpers.updateAttribute in Angular 7. Passing a nullable type should produce the right behaviour, otherwise the attribute would never be removed. Also noticed that it only works with String type. So fields with @HostBinding annotated with other types will fail. This is issue 8 in my list above.

    /// Updates [attribute] on [element] to reflect [value].
    ///
    /// If [value] is `null`, this implicitly _removes_ [attribute] from [element].
   @dart2js.noInline
    void updateAttribute(
        Element element,
        String attribute,
         String? value,
     ) {
         if (value == null) {
             element.removeAttribute(attribute);
         } else {
             setAttribute(element, attribute, value);
         }
         domRootRendererIsDirty = true;
    }

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes Optional() injection must be nullable but not Object?

for disableStr, maybe it should be String? get disabledStr => disabled ? 'true' : null; ?

Copy link
Collaborator Author

@dukefirehawk dukefirehawk Oct 27, 2021

Choose a reason for hiding this comment

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

That works. Object? is just an interim fix for running debugger through the builder process to see what type goes where. They will be replacement once the actual type has been figured out.

@@ -120,29 +122,29 @@ class MaterialCheckboxComponent
///
/// `true` will go to checked and `false` will go to unchecked.
@Input()
bool indeterminateToChecked = false;
bool? indeterminateToChecked = false;
Copy link
Collaborator

Choose a reason for hiding this comment

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

any reason to make it nullable ?

@lejard-h
Copy link
Collaborator

Also seeing a lot of commented code, is it ready for review ?

@lejard-h
Copy link
Collaborator

lejard-h commented Oct 23, 2021

I think you guys went too fast on null safety migration, the plan was to make the package compatible with Angular 7 First. I also probably don't have all the infos of what you already done.

Now the package is compatible with Angular 7, can we coordinate here #35 to progressively migrate the package layer by layer.

I suggest we create a new branch null-safety base on master (after this PR #32) then we partially merge the work already done on dev branch following the TODO list in the issue.

I also think changing type to Object is not a good idea, we probably missed something.

@GZGavinZhao GZGavinZhao mentioned this pull request Oct 27, 2021
54 tasks
@GZGavinZhao
Copy link

GZGavinZhao commented Oct 29, 2021

@dukefirehawk Please tell me when you're ready. :)

I recommend not trying to migrate new areas and finish with what you have now. We want to merge this into null-safety branch, which already has some fixes, especially for the deprecated API stuff.

@dukefirehawk
Copy link
Collaborator Author

dukefirehawk commented Oct 31, 2021

@GZGavinZhao @lejard-h This PR can build and compile everything without errors now. However, the examples has runtime issues that need to be addressed. I will also refactor some of the ugly fix later but it would be done as separate small PR. Take a look at the changes. To fix [attr.xxx]="someBool", I have to introduce attributeToString(someBool) into the html code instead of creating a method someBoolStr and do [attr.xxx]="someBoolStr". Let me know if you have better suggestion for this. As mentioned the underlying Angular method only accepts "String?", so every other type except string must be changed for attr.xxx field to bind to string.

@dukefirehawk
Copy link
Collaborator Author

Only the following examples still need some fixing, the rests are working.
Material Auto Suggestion
Material Date Picker
Material Dialog
Material Dropdown Select
Material Expansion Panel
Material Input
Material Menu
Material Popup
Material Select
Material Tab
Material Tooltip
Material Tree

@jodinathan
Copy link
Collaborator

please, can you enlighten me regarding this PR?
I mean, does it make the whole repo null safe? Do you need help?

@dukefirehawk
Copy link
Collaborator Author

@jodinathan This PR brings the whole repo to null safety. Current status is can compile and build everything successful in null safety mode. However, there are still runtime errors in those listed components related to incompatible function types, dynamic type casting and logic that is based on null to work. These errors show up in browser console when clicking through the examples.

@GZGavinZhao
Copy link

Shall I merge what we have now first? @dukefirehawk can list out the parts that are not working, then we can update its status with #35 and address the problems/bugs one by one. This PR is getting huge.

@GZGavinZhao
Copy link

GZGavinZhao commented Nov 8, 2021

@dukefirehawk I just generated a much more comprehensive and powerful CI script. You can pull that to your repo and perhaps get a lot more feedback from it than the useless 30-line script I wrote. :)

@dukefirehawk
Copy link
Collaborator Author

@GZGavinZhao I've checked in the latest fix. The CI is good but seems to have failed at install_protoc.sh. Can you take a look at it? Otherwise, the code can build and run in null safety mode. What's left are running through the examples (mostly working) and fixing the issues (Usually exception with the class and line number of the code displayed in the browser console). Only Material Tree is still pretty broken as incompatible types are being used. If someone want to take a crack at it, let me know.

EXCEPTION: Expected a value of type 'Parent<dynamic, Iterable<OptionGroup<dynamic>>>', but got one of type '_NestedSelectionOptions<dynamic>', package:angular_components/src/material_tree/material_tree_node.dart 52

Further refactoring can also to be done to get rid of ? for Input field but need to be careful as some of them use null check to switch logic.

@GZGavinZhao GZGavinZhao mentioned this pull request Nov 10, 2021
@dukefirehawk
Copy link
Collaborator Author

@GZGavinZhao Your fix on proto works.

@jodinathan
Copy link
Collaborator

isn't the compatible branch merged into this?
I am testing and it is complaining about the ChangeDetection

@dukefirehawk dukefirehawk merged commit ac7b0eb into angulardart-community:dev Nov 10, 2021
@dukefirehawk
Copy link
Collaborator Author

@jodinathan Which component has the issue?

@jodinathan
Copy link
Collaborator

material-tab, material-auto-suggest-input.

@dukefirehawk
Copy link
Collaborator Author

As mentioned, those two components still have some issues. For material-auto-suggest-input, it uses material popup internally which has some logic that seems to suggest that it requires null to work. Once the underlying type becomes non nullable, it just broke. Working on them at the moment. Will use smaller individual PR per component for the change going forward.

@GZGavinZhao
Copy link

@dukefirehawk Can you fill out #35 in the meantime?

@jodinathan
Copy link
Collaborator

As mentioned, those two components still have some issues. For material-auto-suggest-input, it uses material popup internally which has some logic that seems to suggest that it requires null to work. Once the underlying type becomes non nullable, it just broke. Working on them at the moment. Will use smaller individual PR per component for the change going forward.

Out of curiosity... When I fixed the compatible branch the auto-suggest-input was already at OnPush, so why isn't this fixed at this branch?
And why isn't the compatible branch merged into this one?

@dukefirehawk
Copy link
Collaborator Author

dev branch was originally forked from master together along with compatibility branch. It was my bad to jump start the null safety migration a bit too early due to my need of a few components. By the time, some of the fixes went into compatibility branch, null safety work on dev branch has progressed into compiling the examples. I just finished up on what was started instead of left it hanging in a non compilable state. I believe null-safety branch was created with the intention to cherry pick and merge dev branch into compatible branch.

@dukefirehawk dukefirehawk deleted the migrated/bug-fix-1 branch December 3, 2022 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
null safety Related to null safety migration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants