Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@ export function createIgxCustomElement<T>(component: Type<T>, config: IgxNgEleme
for (const method of componentConfig?.methods!) {
elementCtor.prototype[method] = function() {
const instance = this.ngElementStrategy.componentRef.instance;
return this.ngElementStrategy.runInZone(() => instance[method].apply(instance, arguments));
return this.ngElementStrategy.runInZone(() => {
// Angular normally wraps listeners and schedules change detection to preserve Zone.js behavior.
// Like Angular Elements' setInputValue, we notify the scheduler explicitly because custom-element methods bypass that listener path.
// This behavior may change in a future Angular version.
// https://github.com/angular/angular/blob/9a58353b1b680f162a55969965ae6a90ae20316d/packages/core/src/change_detection/scheduling/zoneless_scheduling_impl.ts#L140

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

const result = instance[method].apply(instance, arguments);
this.ngElementStrategy.notifyChanges();
return result;
});
}
}

Expand Down
32 changes: 32 additions & 0 deletions projects/igniteui-angular-elements/src/app/custom-strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,37 @@ describe('Elements: ', () => {
expect(actionStrip.hidden).toBeTrue();
expect(actionStrip.isConnected).toBeTrue();
});

it('should update the UI correctly after invoking a method', async () => {
// Regression coverage for UI updates after removing the zone.js dependency.
const gridEl = document.createElement("igc-grid");
const columnID = document.createElement("igc-column");
columnID.setAttribute("field", "ProductID");
gridEl.appendChild(columnID);
const columnName = document.createElement("igc-column");
columnName.setAttribute("field", "ProductName");
gridEl.appendChild(columnName);

gridEl.data = SampleTestData.foodProductData();
testContainer.appendChild(gridEl);

await firstValueFrom(fromEvent(gridEl, "childrenResolved"));
await firstValueFrom(fromEvent(gridEl, "dataChanged"));

const HIGHLIGHT_ACTIVE_CSS_CLASS = '.igx-highlight__active';
gridEl.findNext("Ch", false ,false);
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 2));

// verify that a cell is highlighted
let highlightedCell = gridEl.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS);
expect(highlightedCell).not.toBeNull();

gridEl.clearSearch();
await firstValueFrom(timer(10 /* SCHEDULE_DELAY */ * 2));

// verify that no cell is highlighted after clearing the search
highlightedCell = gridEl.querySelector(HIGHLIGHT_ACTIVE_CSS_CLASS);
expect(highlightedCell).toBeNull();
});
});
});
12 changes: 10 additions & 2 deletions projects/igniteui-angular-elements/src/app/custom-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentRef, createComponent, DestroyRef, EventEmitter, Injector, QueryList, Type, ViewContainerRef, reflectComponentType } from '@angular/core';
import { ComponentRef, createComponent, DestroyRef, EventEmitter, Injector, QueryList, Type, ViewContainerRef, reflectComponentType, ɵNotificationSource as NotificationSource, } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgElement, NgElementStrategyEvent } from '@angular/elements';
import { fromEvent, Observable } from 'rxjs';
Expand Down Expand Up @@ -70,6 +70,14 @@ class IgxCustomNgElementStrategy extends ComponentNgElementStrategy {
super(_component, _injector, _inputMap);
}

/**
* @hidden @internal
* Expose a mechanism to manually schedule change detection for the component.
*/
public notifyChanges() {
(this as any).cdScheduler.notify(NotificationSource.CustomElement);
}
Comment thread
mddragnev marked this conversation as resolved.

protected override async initializeComponent(element: HTMLElement) {
if (!element.isConnected) {
// D.P. 2022-09-20 do not initialize on connectedCallback that is not actually connected
Expand Down Expand Up @@ -112,7 +120,7 @@ class IgxCustomNgElementStrategy extends ComponentNgElementStrategy {
}
}
// select closest of all possible config parents
let parent = parents[0]?.deref();
const parent = parents[0]?.deref();

// Collected parents may include direct Angular HGrids, so only wait for configured parent elements:
const configParent = configParents.find(x => x!.selector === parent?.tagName.toLocaleLowerCase());
Expand Down
Loading