Retrieving values from multifield component in HTL in AEM 6.5 - aem

I have a multifield component following this format
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Awards List"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/tabs"
type="-nav"/>
<items jcr:primaryType="nt:unstructured">
<awards
jcr:primaryType="nt:unstructured"
jcr:title="Awards Properties"
sling:resourceType="granite/ui/components/foundation/section">
<layout
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"/>
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<description
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textarea"
fieldLabel="Description"
name="./description"/>
<awards
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
composite="{Boolean}true"
fieldLabel="Awards">
<field
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container"
name="./awards">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<awardtype
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldDescription="Select Award Type"
fieldLabel="Award Type"
name="./type">
<items jcr:primaryType="nt:unstructured">
<gold
jcr:primaryType="nt:unstructured"
text="gold"
value="gold"/>
<silver
jcr:primaryType="nt:unstructured"
text="silver"
value="silver"/>
<bronze
jcr:primaryType="nt:unstructured"
text="bronze"
value="bronze"/>
<other
jcr:primaryType="nt:unstructured"
text="other"
value="other"/>
</items>
</awardtype>
<award
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldDescription="Name of Award"
fieldLabel="Award Name"
name="./award"/>
</items>
</column>
</items>
</field>
</awards>
</items>
</column>
</items>
</awards>
</items>
</content>
</jcr:root>
And I'm trying to just output the contents of the multifield into a list.
And I'm attempting to do so with
<ul data-sly-list="${properties.awards}">
<li>${item.type}</li>
</ul>
But it doesn't render anything. As a test I did
<ul data-sly-list="${[1,2,3,4]}">
<li>${item}</li>
</ul>
Which did work. Looking online I found resources like https://helpx.adobe.com/experience-manager/using/aem65_coral_resourcetypes.html#UseaDataSourceObjecttopopulateaSelectfield
But they seem to be using Java classes to generate the multifield and I'm hoping that's not necessary. I don't need any extra logic all I'm trying to do is display the values of the fields.
Is there something I'm doing wrong? Does using multifields require making a Java class to handle it?
EDIT: I've tried getting the content using a javascript object by having a js file with the contents
"use strict";
use(function () {
var description = granite.resource.properties["description"];
var awards = granite.resource.properties["awards"];
return {
description: description,
};
});
and using
<div data-sly-use.awardsObject="awardslist.js">
<p>
${awardsObject.description}
${awardsObject.awards}
</p>
</div>
But I can't get awards to return anything. I've tried stringifying the awards object to see if I get any data, but I get none.

It is probably because you are using a composite multifield (look at the property composite="{Boolean}true" against the multifield) which generally handles the form content as composite and creates child nodes under the current component to hold the property values.
Quoting from the docs
true to handle the form content value as composite.
Composite multifield supports nesting another multifield (composite or
not). However, non-composite one doesn’t support nesting.
For example, given the name property of field is addresses, and the
descendant fields have following name property values:
street1
street2
postcode
city/name
city/state
city/country/name
gps/lat
gps/long
it would save the following structure in the repository:
+ addresses + item0
- street1
- street2
- postcode
+ city
- name
- state
+ country
- name
+ gps
- lat
- long + item1
- street1
- street2
- postcode
+ city
- name
- state
+ country
- name
+ gps
- lat
- long
Since the properties object only holds the properties of the current resource, ${properties.awards} would be null and hence it doesn't display anything.
It would be easier to create either a Sling Model or Java / Javascript Use API class to get the list and then use it in the HTL file.
Sample JS Use API
"use strict";
use(function () {
var awards = resource.getChild("awards").listChildren();
return {
awards: awards,
};
});
Sample HTL code
<sly data-sly-use.children="children.js">
<ul data-sly-list.award="${children.awards}">
<li>${award.type}</li>
</ul>
<sly>
Kindly note that the properties object, which is an instance of ValueMap only returns the properties of the current resource. Since the multifield values are stored as child resources, you need to access the child resource first before accessing its properties.

Related

AEM anchor link css class

I managed to display the anchor link option in the RTE for the text component for authoring. Because on our website we have a fixed header, it's offsetting the anchor link.
I could resolve the issue with CSS but supporting that I'd need a CSS class on the anchor links. Could someone advise how to add a 'link-anchor' class to the anchor links in AEM?
<links jcr:primaryType="nt:unstructured" features="[modifylink,unlink,anchor]" />
<uiSettings jcr:primaryType="nt:unstructured">
<cui jcr:primaryType="nt:unstructured">
<inline jcr:primaryType="nt:unstructured" toolbar="[undo#undo,undo#redo,#paraformat,#styles,-,#format,experience-aem#colorPicker,-,#justify,-,#lists,-,subsuperscript#subscript,subsuperscript#superscript,links#modifylink,links#unlink,links#anchor,edit#cut,edit#copy,edit#paste-plaintext,edit#paste-wordhtml,misctools#specialchars,misctools#sourceedit,-,table#table]">
<popovers jcr:primaryType="nt:unstructured">
<format
jcr:primaryType="nt:unstructured"
items="[format#bold,format#italic,format#underline]"
ref="format"/>
<justify
jcr:primaryType="nt:unstructured"
items="[justify#justifyleft,justify#justifycenter,justify#justifyright]"
ref="justify"/>
<lists
jcr:primaryType="nt:unstructured"
items="[lists#unordered,lists#ordered,lists#outdent,lists#indent]"
ref="lists"/>
<styles
jcr:primaryType="nt:unstructured"
items="styles:getStyles:styles-pulldown"
ref="styles"/>
<paraformat
jcr:primaryType="nt:unstructured"
items="paraformat:getFormats:paraformat-pulldown"
ref="paraformat"/>
</popovers>
</inline>
<dialogFullScreen jcr:primaryType="nt:unstructured" toolbar="[undo#undo,undo#redo,#paraformat,-,#format,experience-aem#colorPicker,-,#justify,-,#lists,-,subsuperscript#subscript,subsuperscript#superscript,links#modifylink,links#unlink,links#anchor,edit#cut,edit#copy,edit#paste-plaintext,edit#paste-wordhtml,misctools#specialchars,misctools#sourceedit,-,table#table]">
<popovers jcr:primaryType="nt:unstructured">
<format
jcr:primaryType="nt:unstructured"
items="[format#bold,format#italic,format#underline]"
ref="format"/>
<justify
jcr:primaryType="nt:unstructured"
items="[justify#justifyleft,justify#justifycenter,justify#justifyright]"
ref="justify"/>
<lists
jcr:primaryType="nt:unstructured"
items="[lists#unordered,lists#ordered,lists#outdent,lists#indent]"
ref="lists"/>
<styles
jcr:primaryType="nt:unstructured"
items="styles:getStyles:styles-pulldown"
ref="styles"/>
<paraformat
jcr:primaryType="nt:unstructured"
items="paraformat:getFormats:paraformat-pulldown"
ref="paraformat"/>
</popovers>
</dialogFullScreen>
<tableEditOptions
jcr:primaryType="nt:unstructured"
toolbar="[table#insertcolumn-before,table#insertcolumn-after,table#removecolumn,-,table#insertrow-before,table#insertrow-after,table#removerow,-,table#mergecells-right,table#mergecells-down,table#mergecells,table#splitcell-horizontal,table#splitcell-vertical,-,table#selectrow,table#selectcolumn,-,table#ensureparagraph,-,table#modifytableandcell,table#removetable,-,undo#undo,undo#redo,-,table#exitTableEditing,-]"/>
</cui>
</uiSettings>
Your usecase is a simplified version of this use case - http://experience-aem.blogspot.com/2017/09/aem-63-touch-ui-extend-rich-text-link-dialog-add-rel-select.html.
Instead of adding drop down and 2 way mapping, you just need to hard code class name during save. This worked for me:
Create a clientlib - /apps/myproj/clientlibs/authoring
Add categories cq.authoring.dialog
Add a new js file as rte-link-class.js. Any name and give same name inside js.txt
Add below code in the rte-link-class.js
(function ($) {
"use strict";
var _ = window._,
Class = window.Class,
CUI = window.CUI,
RTE_LINK_DIALOG = "rtelinkdialog";
if (CUI.rte.ui.cui.CuiDialogHelper.eaemExtended) {
return;
}
var EAEMLinkBaseDialog = new Class({
extend: CUI.rte.ui.cui.CQLinkBaseDialog,
toString: "EAEMLinkBaseDialog",
initialize: function (config) {
this.superClass.initialize.call(this, config);
},
dlgToModel: function () {
this.superClass.dlgToModel.call(this);
this.objToEdit.attributes["class"] = "custom-anchor-link";
},
dlgFromModel: function () {
this.superClass.dlgFromModel.call(this);
},
});
CUI.rte.ui.cui.CuiDialogHelper = new Class({
extend: CUI.rte.ui.cui.CuiDialogHelper,
toString: "EAEMCuiDialogHelper",
instantiateDialog: function (dialogConfig) {
var type = dialogConfig.type;
if (type !== RTE_LINK_DIALOG) {
this.superClass.instantiateDialog.call(this, dialogConfig);
return;
}
var $editable = $(this.editorKernel.getEditContext().root),
$container = CUI.rte.UIUtils.getUIContainer($editable),
dialog = new EAEMLinkBaseDialog();
dialog.attach(dialogConfig, $container, this.editorKernel);
return dialog;
},
});
CUI.rte.ui.cui.CuiDialogHelper.eaemExtended = true;
})(jQuery);
After adding link from RTE, it gets saved in jcr like this

List Binding is not bound against a list for /JSONDataSet

I have a JSON model, which I build from a Metadata set.
So I created that JSON array and did the following:
var oModel = new JSONModel({
JSONDataSet: oJSONDataArray
});
this._oFragment.setModel(oModel);
In my fragment, I have a table:
<Table id="tableId" items="{ path:'/JSONDataSet' }">
<columns>
<Column>
<Text text="HeaderColumn1"/>
</Column>
<!-- ... -->
</columns>
<ColumnListItem>
<Text text="{Value1}"/>
<!-- ... -->
</ColumnListItem>
</Table>
Now everything works fine on my fragment. In my list, I'll see all that data from my JSON model, but I still receive this weird error in my console:
List Binding is not bound against a list for /JSONDataSet
How can I solve this issue?
List Binding is not bound against a list for ...
The above error occurs only in ODataListBinding.js and is thrown when the module fails to find the entityset name within the service $metadata document or if the resulting multiplicity is not "*". source
In your case, the framework assumes that JSONDataSet is some entity set name defined in the $metadata which obviously cannot be found. In order to prevent framework to search for that in $metadata, you'll need to tell that JSONDataSet is not from the unnamed default model (ODataModel) but from another model (JSONModel).
Try to give it a name, and assign the name in the binding definitions like this:
const oModel = new JSONModel({
JSONDataSet: /*some data*/
});
this._oFragment.setModel(oModel, "anotherModel");
<Table id="tableId" items="{anotherModel>/JSONDataSet}">
<!-- ... -->
<ColumnListItem>
<Text text="{anotherModel>Value1}"/>
<!-- ... -->
</ColumnListItem>
</Table>
The framework won't try to resolve anotherModel>/JSONDataSet until that model is registered and set to the fragment. The error will be gone since the framework now knows that it's not initializing ODataListBinding but a client ListBinding.
If you take a look at the browser console, probably you have already an error telling you that "the template or factory function was not provided" or something similar.
In the following code, there is something missing
<Table id="tableId" items="{ path:'/JSONDataSet' }">
<columns>
.....
<columns>
</Table>
if you do items="{ path:'/JSONDataSet' }", it means that you want the items in your list to be created dynamically based on the path /JSONDataSet from your model. This path should point to an array of some kind (usually an array of objects). Using UI5 terms, you are trying to use an aggregation binding.
However, how do you want the items in your Table to be created?
That's why you need to provide a template item, declaring an example item inside your table:
<Table id="tableId" items="{ path:'/JSONDataSet' }">
<columns>
.....
<columns>
<items>
<ColumnListItem>
<cells>
<ObjectIdentifier
title="{a}"
text="{b}"/>
<Text
text="{c}" />
</cells>
</ColumnListItem>
</items>
</Table>
See more examples in the UI5 documentation.
In the code above, a, b and c are proprierties found in every object inside you array.
In the end, if you array contains 10 items, 10 rows will be created in your table. If you want to create columns dynamically, just provide a single Column example and use columns="{ path:'/JSONDataSet'} instead.

AEM 6.3 HTL variable usage

I've really new to AEM, and I'm struggling getting with a button component. It has a drop down asking for open type, so either new window or modal. Ideal the gets target="_blank" or data-modal as part of the render.
Here's my dialog:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured"
jcr:title="Button"
sling:resourceType="cq/gui/components/authoring/dialog">
<content
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/fixedcolumns"
margin="{Boolean}false">
<items jcr:primaryType="nt:unstructured">
<column
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<label
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Button label"
name="./label"/>
<linkTo
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
fieldLabel="Link to"
name="./linkTo"
rootPath="/content"
suffix=".html"/>
<cssClass
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
fieldLabel="Css class(es)"
name="./cssClass"/>
<open
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/select"
fieldLabel="Open options"
fieldDescription="A new tab/window, or a modal"
name="./open">
<items jcr:primaryType="nt:unstructured">
<def
jcr:primaryType="nt:unstructured"
text="(default)"
value=""/>
<tab
jcr:primaryType="nt:unstructured"
text="New Tab/Window"
value="target='_blank'"/>
<modal
jcr:primaryType="nt:unstructured"
text="Modal Window"
value="data-xxx"/>
</items>
</open>
<secondary
jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/checkbox"
checked="${not empty cqDesign.useSecondary ? cqDesign.useSecondary : false}"
fieldDescription="Use the secondary style for the button."
name="./useSecondary"
text="Use secondary style"
uncheckedValue="false"
value="{Boolean}true"/>
</items>
</column>
</items>
</content>
</jcr:root>
and here is my button.java
package apps.bbcom_aem_project.components.content.button;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ValueMap;
import com.adobe.cq.sightly.WCMUsePojo;
public class Button extends WCMUsePojo {
public static final Logger log = LoggerFactory.getLogger(Button.class);
public static final String PROP_LINK_TO = "linkTo";
public static final String PROP_LABEL = "label";
public static final String CSS_CLASS = "cssClass";
public static final String OPEN = "open";
private String linkTo;
private String label;
private String cssClass;
private String open;
#Override
public void activate() throws Exception {
Resource resource = getResource();
ValueMap properties = getProperties();
linkTo = properties.get(PROP_LINK_TO, "#");
label = properties.get(PROP_LABEL, "");
cssClass = properties.get(CSS_CLASS, "");
open = properties.get(OPEN, "");
if (StringUtils.isNotEmpty(linkTo) && !"#".equals(linkTo)) {
// is linkTO does not starts with http
if( !linkTo.startsWith("http") ) {
linkTo = linkTo + ".html";
}
}
log.debug("resource: {}", resource.getPath());
log.debug("linkTo: {}", linkTo);
log.debug("label: {}", label);
}
public String getLinkTo() {
return linkTo;
}
public String getLabel() {
return label;
}
public String getCssClass() {
return cssClass;
}
public String getOpen() {
return open;
}
}
At this point I have no errors, and a maven clean install gives no errors.
Here's my current button.html
<div data-sly-test="${wcmmode.edit || wcmmode.design}"><small class="text-muted"><em>Button Component - Configure</em></small></div>
<a data-sly-use.button="Button" data-sly-test="${button.label != ''}" class="btn ${properties.useSecondary ? 'btn-secondary' : 'btn-primary'} ${button.cssClass}" href="${button.linkTo}" role="button" data-opentype="${button.open}" ${button.open} >${button.label} ${button.open}</a>
and when I inspect the element, I see this:
<a class="btn btn-secondary " href="#" role="button" data-opentype="data-xxx" ${button.open}="">Workspaces data-xxx</a>
The data-xxx matches what I selected in the component options, but I can't get that to render in the opening tag.
HTL (previously known as Sightly) uses HTML5 data attributes to define statements over blocks of markup.
This markup is missing the data attribute, so is not HTML5 compliant
<a ... ${button.open}></a>
You can use the data-sly-attribute statement to set the attribute but you required to pass a key-value pairs map object
<a ... data-sly-attribute="${button.open}"></a>
This will output
<a .... target="_blank"></a>
Also you should consider moving from WCMUsePojo to Sling Models as is recommended by Adobe
The syntax <a ${button.open}=""></a> would not work as it is not part of the HTL spec. If you want to render an attribute name AND value you must use:
<a data-sly-attribute="${button.open}"></a>
Please note that button.open must be an object, preferably a map, for example
{"data-xxx":""}
This will render:
<a data-xxx=""></a>
please refer to the data-sly-attribute spec
Here's my solution:
<div data-sly-test="${wcmmode.edit || wcmmode.design}"><small class="text-muted"><em>Button Component - Configure</em></small></div>
<sly data-sly-test="${properties.open == 'tab'}">
<a data-sly-use.button="Button" data-sly-test="${button.label != ''}" class="btn ${properties.useSecondary ? 'btn-secondary' : 'btn-primary'} ${button.cssClass} tab" href="${button.linkTo}" role="button" target="_blank" > ${button.label} ${button.open} </a>
</sly>
<sly data-sly-test="${properties.open == 'modal'}">
<a data-sly-use.button="Button" data-sly-test="${button.label != ''}" class="btn ${properties.useSecondary ? 'btn-secondary' : 'btn-primary'} ${button.cssClass} modal" href="${button.linkTo}" role="button" data-lity > ${button.label} ${button.open} </a>
</sly>
<sly data-sly-test="${!properties.open}">
<a data-sly-use.button="Button" data-sly-test="${button.label != ''}" class="btn ${properties.useSecondary ? 'btn-secondary' : 'btn-primary'} ${button.cssClass}" href="${button.linkTo}" role="button" > ${button.label} ${properties.open} </a>
</sly>
It's not the cleanest, but as I only have two options, it seems to work.

How to create multi image component with image preview In adobe cq5?

I want to build a component in which user can drag & drop two images from content finder. For this i created another tab in my dialog but when i am authoring the component its showing the 1st tab image in both div's. Can you please tell me where i'm wrong here is my code.
dialog.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Dialog"
activeTab="{Long}0"
helpPath="en/cq/current/wcm/default_components.html#Image"
xtype="tabpanel">
<items jcr:primaryType="cq:WidgetCollection">
<image
jcr:primaryType="cq:Widget"
cropParameter="./imageCrop"
ddGroups="[media]"
fileNameParameter="./fileName"
fileReferenceParameter="./fileReference"
mapParameter="./imageMap"
name="./file"
requestSuffix=".img.png"
rotateParameter="./imageRotate"
title="Image"
xtype="html5smartimage"/>
<advanced
jcr:primaryType="cq:Widget"
title="Advanced"
xtype="panel">
<items jcr:primaryType="cq:WidgetCollection">
<title
jcr:primaryType="cq:Widget"
fieldLabel="Title"
name="./jcr:title"
xtype="textfield"/>
<alt
jcr:primaryType="cq:Widget"
fieldDescription="(leave empty to use the title defined above)"
fieldLabel="Alt Text"
name="./alt"
xtype="textfield"/>
<linkURL
jcr:primaryType="cq:Widget"
fieldDescription="Drop files or pages from the Content Finder"
fieldLabel="Link to"
name="./linkURL"
xtype="pathfield"/>
<description
jcr:primaryType="cq:Widget"
fieldLabel="Description"
name="./jcr:description"
xtype="textarea"/>
<size
jcr:primaryType="cq:Widget"
fieldLabel="Size"
heightParameter="./height"
widthParameter="./width"
xtype="sizefield"/>
</items>
</advanced>
<image4
jcr:primaryType="cq:Widget"
cropParameter="./image4Crop"
ddGroups="[media]"
fileNameParameter="./image4/fileName"
fileReferenceParameter="./image4/fileReference"
mapParameter="./imageMap"
name="./image4/file"
requestSuffix=".img.png"
rotateParameter="./image4/imageRotate"
title="Image"
xtype="html5smartimage"/>
</items>
</jcr:root>
image.jsp is
<%# page import="com.day.cq.commons.Doctype,
com.day.cq.wcm.api.components.DropTarget,
com.day.cq.wcm.foundation.Image" %><%
%><%#include file="/libs/foundation/global.jsp"%><%
Image image = new Image(resource);
//drop target css class = dd prefix + name of the drop target in the edit config
image.addCssClass(DropTarget.CSS_CLASS_PREFIX + "image");
image.loadStyleData(currentStyle);
image.setSelector(".img"); // use image script
image.setDoctype(Doctype.fromRequest(request));
Image image4 = new Image(resource);
//drop target css class = dd prefix + name of the drop target in the edit config
image4.addCssClass(DropTarget.CSS_CLASS_PREFIX + "image4");
image4.loadStyleData(currentStyle);
image4.setSelector(".img"); // use image script
image4.setDoctype(Doctype.fromRequest(request));
// add design information if not default (i.e. for reference paras)
if (!currentDesign.equals(resourceDesign)) {
image.setSuffix(currentDesign.getId());
}
String divId = "cq-image-jsp-" + resource.getPath();
%><div id="<%= divId %>"><% image.draw(out); %></div><%
%><cq:text property="jcr:description" placeholder="" tagName="small" escapeXml="true"/>
<div id="<%= divId %>"><% image4.draw(out); %></div>
<%#include file="/libs/foundation/components/image/tracking-js.jsp"%>
I ran into a problem like this using with multiple images within the dialog. You might check the resourceType after you save the images in CRXDE to make sure they both have a resourceType property set. If either images are missing this property you can add the property using a hidden widget. Reference https://forums.adobe.com/message/4623838 for more
<resType1
jcr:primaryType="cq:Widget"
ignoreData="{Boolean}true"
name="./file/sling:resourceType"
value="foundation/components/image"
xtype="hidden"/>
<resType2
jcr:primaryType="cq:Widget"
ignoreData="{Boolean}true"
name="./image4/sling:resourceType"
value="foundation/components/image"
xtype="hidden"/>

How to dynamically load an XML fragment in XML view?

Suppose I have the following XML view:
<mvc:View xmlns:mvc="sap.ui.core.mvc" ...>
<Page>
<content>
<l:VerticalLayout>
<l:content>
<core:Fragment fragmentName="my.static.Fragment" type="XML" />
</l:content>
</l:VerticalLayout>
</content>
</Page>
</mvc:View>
The fragment my.Fragment is statically loaded. However, I now want to dynamically change the to-be-loaded fragment (ideally using data binding the fragmentName property, but any other means should be ok as well), ie. something like this:
<mvc:View xmlns:core="sap.ui.core.mvc" ...>
<Page>
<content>
<l:VerticalLayout>
<l:content>
<core:Fragment fragmentName="{/myDynamicFragment}" type="XML" />
</l:content>
</l:VerticalLayout>
</content>
</Page>
</mvc:View>
However, the latter does not work, and the Fragment definitions don't allow for data binding... I might have missed something, but how should I dynamically change the Fragment in my XML view based on a parameter/model property/etc?
For now, I have resorted to a custom control instead of directly using a fragment in my view, and have that control do the dispatching to the appropriate Fragment, but I feel there should be an easier, out-of-the-box way...
I think the only solution will be initialization of fragment from onInit method of controller:
sap.ui.controller("my.controller", {
onInit : function(){
var oLayout = this.getView().byId('mainLayout'), //don't forget to set id for a VerticalLayout
oFragment = sap.ui.xmlfragment(this.fragmentName.bind(this));
oLayout.addContent(oFragment);
},
fragmentName : function(){
return "my.fragment";
}
});
The fragment name can also result from a binding, including an expression binding which evaluates to a constant. As formatter functions return strings, and not booleans, === 'true' has been added in the following example:
Example: Dynamic Fragment Name
<core:Fragment fragmentName="{= ${path: 'facet>Target', formatter: 'sap.ui.model.odata.AnnotationHelper.isMultiple'} === 'true'
? 'sap.ui.core.sample.ViewTemplate.scenario.TableFacet'
: 'sap.ui.core.sample.ViewTemplate.scenario.FormFacet' }" type="XML"/>