Hello,
I am continuing the journey of migrating from Au1 to Au2, and have reached the point of integrating Devextreme (from DevExpress), which I will abbreviate as Dx.
BACKGROUND
In our Au1 application, I have successfully integrated Dx, even to the extent of marrying Aurelia’s templating to Dx’s templating through the integrationOptions
property on those Dx components which support dx-template
s.
It would appear that a number of API’s have moved, changed, or been eliminated. Consider the imports from my DxAuTemplateService
:
import { inject, TemplatingEngine, View, ViewResources } from 'aurelia-framework';
import { createOverrideContext } from 'aurelia-binding';
Of course, I now import inject
from ‘aurelia’.
I know from the documentation that TemplatingEngine
is now under the Enhance API in Au2. And that’s fine. I just have to change the method call to reflect the new signature (I’ll work on that later). From our Au1 application, I have:
// Here, we build an Aurelia view from all of the moving parts
const view = this.templatingEngine.enhance({
element: element,
bindingContext: itemBindingContext,
overrideContext: itemOverrideContext,
resources: viewResources,
});
Finally, it would appear that @noView
and @processContent
have changed as well. I haven’t been able to migrate the following use case (i.e., the specific combination of the two decorators below):
@noView()
@processContent(false)
export class TsiDxButton() {
...
}
I learned the above approach from the two Vimeo training courses offered by Rob Eisenberg himself a number of years ago (see Question #3 below for a fuller discussion).
Also, know that I have successfully wrapped DxButton from Dx, but have not yet been able to bring Aurelia’s templates together with Dx’s. That’s what the questions below address.
QUESTIONS
1. What happened to #createOverrideContext
?
import { createOverrideContext } from 'aurelia-binding';
I use it in the following way (first branch of the if
below):
...
if (model) {
itemBindingContext = {
data: model, // Push an Aurelia model into the data property
};
// Not strictly necessary, but assists Aurelia with scope hierarchy traversal
itemOverrideContext = createOverrideContext(
scope.bindingContext,
scope.overrideContext
);
} else {
// Here, we just reuse the parent scope; not all dx-templates are associated with
// data (a model)
itemBindingContext = scope.bindingContext;
itemOverrideContext = scope.overrideContext;
}
const view = this._createAureliaViewFromTemplate(
newElement,
itemBindingContext,
itemOverrideContext,
scope.owningView.resources
);
...
2. What happened to ViewResources
?
I know that View
is now EnhancedView
. But what happened to ViewResources
? I use them only in contract language to make sure I’m working with instances of these classes. So they aren’t strictly necessary for the template service to work. But I place many contracts around third-party API usages in order to detect intimate changes in those APIs:
...
require: {
element, 'Element exists';
itemBindingContext, 'Item binding context exists';
itemOverrideContext, 'Item override context exists';
viewResources instanceof ViewResources,
'View resources are of type ViewResources (Aurelia)';
}
...
return view;
ensure: {
result, 'Aurelia view exists';
result instanceof View, 'View is of type View (Aurelia)';
// I know that View will become EnhancedView
}
3. How do we migrate the following decorator chord?:
@noView()
@processContent(false)
With Dx components, @noView
allows the component to take over the view. I have determined that the new pattern for that in Au2 is the following:
@customElement({
name: 'dx-button',
template: null,
)
where template: null
is the equivalent of @noView
.
@processContent
is a bit trickier. Consider the following two snippets from our Au1 application:
@noView
@processContent(false)
@inject(Element, DxAuIntegrationService, CustomEventDispatcher)
export class DxSelectBox extends DxTextualInputBase {
...
}
<dx-select-box items.bind="typeOptions" value-expr="id"...>
<dx-template name="item">
<div innerhtml.bind="data.type"></div>
</dx-template>
<dx-template name="field">
<dx-text-box is-static.bind="true" value.bind="data.typeUnformatted">
</dx-text-box>
</dx-template>
</dx-select-box>
It would appear that Au2 strips out anything between the custom element’s tags. The way my template services works, I harvest the DX-TEMPLATE
elements, ingest them into the template dictionary, and then pass that dictionary to the Dx component’s integrationOptions
, as specified by the DevExpress team. After the ingest, I delete the DX-TEMPLATE
elements as they are no longer needed.
@processContent(false)
simultaneously allows me to have content but suppress it in the view (because it’s going to be processed by me and removed).
How do achieve this scenario in Au2? This was explicitly covered in Rob’s course, and I use it in our Au1 application with great success!