Skip to content

NgClass removes existing class when applying array that contains with 2 empty slots #17852

Closed

Description

@wizarrc

I'm submitting a ...


[ ] Regression (behavior that used to work and stopped working in a new release)
[x] Bug report 
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Construct a class array with 4 strings. The middle classes are an empty string. Then change the 2nd class, leaving the other classes unchanged.

Current behavior

NgClass does not apply correct classes. It removes the last class from the array. Internally the last class is added to the add and remove list, and since the add class code does nothing since it's already in the list and does not error, the remove list removes the class.

Expected behavior

NgClass apply correct classes. The action should be to do nothing for the other existing classes and only add the 2nd class.

The following code tries to add the existing class in changes.forEachAddedItem, then removes it in changes.forEachRemovedItem. I would suggest not only fixing the bug, but reverse the order to first remove, then add, in case there are more bugs in the future.

https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_class.ts#L105

private _applyIterableChanges(changes: IterableChanges<string>): void {
    changes.forEachAddedItem((record) => {
      if (typeof record.item === 'string') {
        this._toggleClass(record.item, true);
      } else {
        throw new Error(
            `NgClass can only toggle CSS classes expressed as strings, got ${stringify(record.item)}`);
      }
    });

    changes.forEachRemovedItem((record) => this._toggleClass(record.item, false));
}

Minimal reproduction of the problem with instructions

http://plnkr.co/edit/bTsnyx1EciH66tRROu5o?p=preview

What is the motivation / use case for changing the behavior?

Developers expect binding to be correct.

Please tell us about your environment


Angular version: 4.2.4


Browser:
- [x] Chrome (desktop) version 59
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [x] Edge version 15
 
For Tooling issues:
- Node version: XX 
- Platform: 

Others:

Updated all NgStyle to NgClass - sorry for the brain fart.

Activity

  1. tytskyi commented on Jun 29, 2017

    @tytskyi
    1. Incorrect issue title, you do refer to [ngClass], not NgStyle

    2. Developers expect binding to be correct.

      To not have such surprises do not use [ngClass]

      see Add ngAttr like ngClass and ngStyle #13940 (comment)

      and feat(common): introduce ngAttr directive #13958 (comment)

    Perfect use-case for [ngClass] - is to generate dynamic class-name in runtime. When you don't know class in advance, for example [ngClass]="getMyRandomClassName()". Or attaching multiple classes at once. Everything else could be solved within [class.class-name]="true" binding.

    Related issues that i found quickly:

  2. changed the title [-]NgStyle removes existing style when applying array that contains with 2 empty slots[/-] [+]NgClass removes existing style when applying array that contains with 2 empty slots[/+] on Jun 29, 2017
  3. wizarrc commented on Jun 29, 2017

    @wizarrc
    Author

    @tytskyi

    1. I updated the typo in the title. I will change to ngClass everywhere shortly, as this is not ngStyle.
    2. Thanks for the workarounds. I should have listed it along with my bug report.

    I looked at the 4 related issues you listed, and all but the top one is closed. Does that mean they are already fixed or won't fix? The top related issue mentions using both ngClass and class. I am only using ngClass in my repo. I think this is a separate issue.

    Anyways, here is a precise case where it fails, and is clearly a bug. If you debug the code, you can see that it adds the class to both the add and remove list during the ngDoCheck call in ngClass.

  4. changed the title [-]NgClass removes existing style when applying array that contains with 2 empty slots[/-] [+]NgClass removes existing class when applying array that contains with 2 empty slots[/+] on Jun 29, 2017
  5. vicb commented on Jun 29, 2017

    @vicb
    Contributor

    That is definitely a bug in the iterable differ

  6. wizarrc commented on Jun 30, 2017

    @wizarrc
    Author

    @vicb I think you are right.

    https://github.com/angular/angular/blob/master/packages/core/src/change_detection/differs/default_iterable_differ.ts#L196

    On the third item check, I took a screen shot before and after it calls _verifyReinsertion. It looks like the record it is returning is also being used to progress to the next record, which in this case, is causing the record to show it being added and then deleted.

    Before:
    before-verifyreinsertion

    After:
    after-verifyreinsertion

    Could the fix be as simple as the following?

    // Create a temp variable so as to not affect the next record in the loop
    let checkRecord = record;
    if (mayBeDirty) {
        // TODO(misko): can we limit this to duplicates only?
        checkRecord = this._verifyReinsertion(checkRecord, item, itemTrackBy, index);
    }
    if (!looseIdentical(checkRecord.item, item)) this._addIdentityChange(checkRecord, item);
    

    so record is not changed for when it calls record = record._next;.

  7. wizarrc commented on Jun 30, 2017

    @wizarrc
    Author

    I updated the repo to show duplicated data using only the DefaultIterableDiffer along with output from the added and removed list..

    http://plnkr.co/edit/WPWy2Nx0B4LErW7dxQKK?p=preview

  8. vicb commented on Jun 30, 2017

    @vicb
    Contributor

    Thanks guys for helping in debugging this issue, that's really appreciated !

    @wizarrc the fix is probably along the lines of what you have proposed. I'll double check tomorrow.

  9. self-assigned this
    on Jun 30, 2017
  10. wizarrc commented on Jun 30, 2017

    @wizarrc
    Author

    @vicb No problem. Once I figure out the build system, I could test my proposals and submit PRs, until then, that's the best I can do.

  11. vicb commented on Jun 30, 2017

    @vicb
    Contributor

    Your are probably looking for ./test.sh browserNoRouter ?

  12. wizarrc commented on Jun 30, 2017

    @wizarrc
    Author

    @vicb I'm pretty sure that's bash talk. I'm coming from the command prompt and PowerShell (bat/ps1 scripts) world. I don't suppose there is vanilla Windows support for building angular? Once Bash for Windows is enabled by default, I will be taking a look into that, but right now it's still kinda beta.

  13. 6 remaining items

  14. wizarrc commented on Jun 30, 2017

    @wizarrc
    Author

    @vicb LGTM

    I think I understand better how the differ works now. It's a complicated data structure. I'd have to really break it down sometime when I need a good puzzle.

  15. added a commit that references this issue on Jun 30, 2017
    7261b03
  16. vicb commented on Jul 1, 2017

    @vicb
    Contributor

    Thanks for the feedback - and contact me if you like puzzles we probably can find some issues for you to work on :)

  17. wizarrc commented on Jul 3, 2017

    @wizarrc
    Author

    @vicb I'd love to, right now I am still having lots of issues getting angular to build on windows. The build.sh script added rsync commands back in February and I think I found workarounds, including manually adding a junction directory that's out of date in the scripts\windows\create-symlinks.sh script, upgrading node to version 6, even though the DEVELOPER.md says version < 6, and modifying the build script to workaround using root directories with rsync. I'm still hanging the process with warning messages. Windows support seems to be a real mess at the moment.

    I posted my progress here: #17894 (comment)

    Any help getting that working would greatly help me to get involved.

  18. added 4 commits that reference this issue on Jul 6, 2017
    c69fff1
    a318093
    83cd727
  19. added a commit that references this issue on Aug 11, 2017
    893c08b
  20. added a commit that references this issue on Aug 28, 2017
    22ff40b
  21. angular-automatic-lock-bot commented on Sep 12, 2019

    @angular-automatic-lock-bot

    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.

  22. locked and limited conversation to collaborators on Sep 12, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions