ngClass behaving differently than regular classes with cdk-drag-drop
See original GitHub issueI have different types of elements in my *cdkDropList
that need different placholder hights when dragging them around. Since the array has objects with a property type
, I added those types as CSS classes and tried to add them dynamically using [ngClass]
. However, these dynamically generated classes behave differently than when I’m setting them as “regular” CSS classes.
This is what happens, when I set the classes dynamically:
The placeholder and the elements in the dropList
overlap. Here’s the relevant code:
example.component.ts
contentItems: ContentItem[] = [
{ type: 'text', /* more props */ },
{ type: 'text', /* more props */ },
{ type: 'image', /* more props */ }
];
example.component.html
<div *ngFor="let item of contentItems" class="editor-item" cdkDrag>
<div [ngClass]="['dropzone-placeholder', item.type]" *cdkDragPlaceholder>
<p>{{ 'EDITOR.INSERT HERE' | translate }}</p>
</div>
<app-language-tab-editor *ngIf="item.type === 'text'"></app-language-tab-editor>
<app-image-upload *ngIf="item.type === 'image'"></app-image-upload>
</div>
example.component.scss
$dropzone-placeholder-dark: #00973B;
$dropzone-placeholder-light: #00973B0D;
$text-placeholder-height: 135px;
$image-placeholder-height: 375px;
.dropzone-placeholder {
border: 1px dashed $dropzone-placeholder-dark;
color: $dropzone-placeholder-dark;
background: $dropzone-placeholder-light;
&.text {
height: $text-placeholder-height;
}
&.image {
height: $image-placeholder-height;
}
}
I currently only have two different types, but the goal is to make it easily expandable to add more later on. I have also already tried to instead use class="dropzone-placeholder {{ item.type }}"
as well as [class]="'dropzone-placeholder ' + item.type"
, to no avail.
After further testing I have also found out, that it generally doesn’t work using [ngClass]
, even if we don’t use a variable. Using [ngClass]="['dropzone-placeholder', 'text']"
didn’t work either.
This is the expected behaviour:
The placeholder and the elements in the dropList
don’t overlap and are instead placed properly below each other. This behaviour can currently only be achieved by setting the classes regularily, but the HTML is rather unpleasant to look at, since the code would get messily redundant in the future:
example.component.html
<div *ngFor="let item of contentItems" class="editor-item" cdkDrag>
<div *ngIf="item.type === 'text'">
<div class="dropzone-placeholder reorder text" *cdkDragPlaceholder>
<p>{{ 'EDITOR.INSERT HERE' | translate }}</p>
</div>
</div>
<div *ngIf="item.type === 'image'">
<div class="dropzone-placeholder reorder image" *cdkDragPlaceholder>
<p>{{ 'EDITOR.INSERT HERE' | translate }}</p>
</div>
</div>
<app-language-tab-editor *ngIf="item.type === 'text'"></app-language-tab-editor>
<app-image-upload *ngIf="item.type === 'image'"></app-image-upload>
</div>
Environment
- Angular: v8.3.25
- CDK: v8.2.3
- Browser(s): Chrome, Firefox
- Operating System: Windows 10 (1803)
Issue Analytics
- State:
- Created 4 years ago
- Comments:5 (1 by maintainers)
Top GitHub Comments
@mladenbrankovic The problem is because you are specifying
height
values in your dynamic classes that change thediv
geometry…but these dynamic classes only get added after change detection runs on the template. I don’t know all the details, but I think the CDK code starts “using” this placeholder template before its first change detection run.See this StackBlitz.
This demo includes a monkey patched
_createPlaceholderElement()
method. The only new code line is the one outlined in comments, manually triggering change detection on the dynamically instantiated template. Adding this line makes the placeholder work properly - comment it out to see otherwise.It is still somewhat hard to see exactly what is going on with your drag setup based on those two images, but I think the above should fix it. I would try adding that monkey patch code to your project and see if it fixes the problem.
@crisbeto What are your thoughts on adding the
detectChanges()
line to_createPlaceholderElement()
as well as_createPreviewElement()
immediately after dynamic template instantiation?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.