The multifield xtype's field config takes only one item (i.e you can have one textfield in it. When multiple values are configured they will be stored as a multivalued property called links and when only one value is configured it'll be stored as a single valued property called links). The entire data configured in your multifield will be stored as links property in your node. You won't be able to get them as "jcr:title" and "jcr:url".
You should create a custom xtype say "linksXtype" that stores the "jcr:title" and "jcr:url" as a single string separated by some pattern say "***" ("jcr:title***jcr:url").
You can find the details of creating a custom xtype here : link
The xtype can be created like this:
Ejst.CustomWidget = CQ.Ext.extend(CQ.form.CompositeField, {
/**
* @private
* @type CQ.Ext.form.TextField
*/
hiddenField: null,
/**
* @private
* @type CQ.Ext.form.ComboBox
*/
jcrtitle: null,
/**
* @private
* @type CQ.Ext.form.TextField
*/
jcrurl: null,
constructor: function(config) {
config = config || { };
var defaults = {
"border": false,
"layout": "table",
"columns":2
};
config = CQ.Util.applyDefaults(config, defaults);
Ejst.CustomWidget.superclass.constructor.call(this, config);
},
// overriding CQ.Ext.Component#initComponent
initComponent: function() {
Ejst.CustomWidget.superclass.initComponent.call(this);
this.hiddenField = new CQ.Ext.form.Hidden({
name: this.name
});
this.add(this.hiddenField);
this.jcrtitle = new CQ.Ext.form.TextField({
fieldLabel:"Jcr url",
cls:"ejst-customwidget-1",
listeners: {
change: {
scope:this,
fn:this.updateHidden
}
},
optionsProvider: this.optionsProvider
});
this.add(this.jcrtitle);
this.jcrurl = new CQ.Ext.form.TextField({
fieldLabel:"Jcr Title",
cls:"ejst-customwidget-2",
listeners: {
change: {
scope:this,
fn:this.updateHidden
}
}
});
this.add(this.jcrurl);
},
// overriding CQ.form.CompositeField#setValue
setValue: function(value) {
var parts = value.split("/");
this.jcrtitle.setValue(parts[0]);
this.jcrurl.setValue(parts[1]);
this.hiddenField.setValue(value);
},
// overriding CQ.form.CompositeField#getValue
getValue: function() {
return this.getRawValue();
},
// overriding CQ.form.CompositeField#getRawValue
getRawValue: function() {
return this.jcrtitle.getValue() + "***" +
this.jcrurl.getValue();
},
// private
updateHidden: function() {
this.hiddenField.setValue(this.getValue());
}
});
// register xtype
CQ.Ext.reg('linksXtype', Ejst.CustomWidget);
change the dialog.xml to something like this
<?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"
title="dialog"
xtype="dialog">
<items jcr:primaryType="cq:WidgetCollection">
<links
jcr:primaryType="cq:Widget"
fieldLabel="QuickLinks"
name="./links"
xtype="multifield">
<fieldConfig
jcr:primaryType="cq:Widget"
xtype="linksXtype">
</fieldConfig>
</links>
</items>
</jcr:root>
To fetch the values iterate over the string array stored as links property and split each string by "***"
EDIT :
Adobe consultancy services under its ACS-Commons package provides a more elegant multifieldpanel widget to handle this use case. It simplifies the approach and eliminates the need to write a custom xtype for every combination of required fields. The data is stored in form of JSON format and comes with taglibs to extract data from the node. Link : http://adobe-consulting-services.github.io/acs-aem-commons/features/widgets.html#multi-field-panel-since-150