Hi,
To give an answer to the question "Contrained by". You can find the answer in a combination of both the Mendix Client API documentation and the XML reference Guide that can be found if you go to "http://developers.mendix.com" -> "How to's" -> "Custom Widget Development" -> "XML reference guide":
https://world.mendix.com/display/howto50/XML+Reference+Guide
There you will find all the property possibilities you can configure for your custom widgets. Including an example how to configure a property that allows you to set a constraint.
EntityConstraint Property
The EntityConstraint lets you put a constraint on either the entity you specify with entityProperty or, if needsEntityContext is set to true and no entityProperty is defined, to the entity passed as context.
<property key="constraint" type="entityConstraint" entityProperty="color">
<caption>Color constraint</caption>
<category>Data source</category>
<description>The xpath constraint on the entity.</description>
</property>
Now there is a pitfall in setting a constraint. An entityConstraint only works when you search for entities through an XPATH mx.data.get request:
Getting an object through XPath
mx.data.get({
xpath: "//MyModule.Entity[" + this.constraint + "]",
callback : function(objs) {
console.log("Received " + objs.length + " MxObjects");
}
}, this);
You can normally configure something like [%CurrentObject%] inside your constraint. This is not supported out of the box by just composing the XPATH through a custom widget property as you see in the example above.
So how to do this?!??
Example combining [%CurrentObject%] in constraint
// From the AppStoreWidgetBoilerplate
postCreate: function (obj, callback) {
this._contextObj = obj // Will get the MxObj and remember this inside your widget.
}
...
_updateRendering: functing (callback) {
var alteredConstraint = this.constraint.split("[%CurrentObject%]").join(this._contextObj.getGuid()),
contraintComposed = "//MyModule.Entity[MyModule.MyReference_OtherEntity/MyModule.OtherEntity=" + this.alteredConstraint + "]";
mx.data.get({
xpath: contraintComposed,
callback : function(objs) {
console.log("Received " + objs.length + " MxObjects");
}
}, this);
callback();
}
The MxObject you receive in postCreate can be saved in your widget with this._contextObj. Then in the _updateRendering you can get it's GUID and replace the text (string) "[%CurrentObject%]" with this GUID. The following helper class can get your parts of your XPATH that you need to construct a proper XPATH with constraint.
Helper Class
define([], function() {
'use strict';
return function() {
return {
xpath: {
getLastAttribute: function (xpath) {
var xpathParts = xpath.split('/');
return xpathParts[ xpathParts.length - 1 ];
},
getLastEntity: function (xpath) {
var xpathParts = xpath.split('/');
xpathParts.pop();
return xpathParts[ xpathParts.length - 1 ];
},
getReference: function (xpath) {
var xpathParts = xpath.split('/');
return xpathParts[ 0 ];
},
noAttribute: function (xpath) {
var xpathParts = xpath.split('/'),
noAttributeXpathPath = null;
xpathParts.pop();
noAttributeXpathPath = xpathParts.join('/');
return noAttributeXpathPath;
},
noLastEntity: function (xpath) {
var xpathParts = xpath.split('/'),
noAttributeXpathPath = null;
xpathParts.pop();
noAttributeXpathPath = xpathParts.join('/');
return noAttributeXpathPath;
},
reverse: function (xpath) {
var xpathParts = xpath.split('/'),
reverseXpathPath = null;
xpathParts.reverse();
reverseXpathPath = xpathParts.join('/');
return reverseXpathPath;
},
buildReverseXpath: function (xpath) {
var newXpath = '//' + this.getLastEntity(xpath) + '[';
newXpath += this.reverse(this.noLastEntity(this.noAttribute(xpath)));
newXpath += ' = \'[%CurrentObject%]\']';
return newXpath;
},
replaceCurrentObject: function (xpath, obj) {
return xpath.split('[%CurrentObject%]').join(obj.getGuid());
}
}
};
};
});
Hopes this will help you out.
Hi,
Your thinking is correct. And you should implement it that way. If you wish to dynamicly / magicly descover references and start to attach your widget to changes on entities that might over association be connected to some entity.
Take a look at the "this.subscribe" to hook your widget to updates on the collected entiteit. Getting mxobject over association can also be written a bit easier with a function called .fetch. That is available on each mxobject.
But remember using these functions might trigger allot of requests to the server. It is always recommended to look how you can simplify your widget so that it can work with eighter one or over one assiociation related entity.
You are getting freedom in the Mendix Client API. But with freedom there comes a great responsebility.
Sometimes collecting complex data structures can just performance wise be better done with a custom requesthandler. That returns JSON.
Hi Richard,
thanks for the elaborate answer on how to apply the context itself.
By the looks of it when i have the context object GUID, i should be able to call retrieve any GUID's related to my context entity? with
mendix.lib.MxMetaObject.getReferenceAttributes()
which should then allow me to retrieve the existing references by mendix.lib.MxObject.getReferences()
which should then allow me to get their GUID's and track any changes made to those entities whenever the context is loaded/updated, if these are not empty i should be able to include them in my constaint for the reference i'm trying to select?
Is my thinking here correct? Or do you see any limitations?
So the scenario i'm trying to cover is, my context object has 2 or more reference selectors, and these references should limit each other too. I think my thoughts above are complex but should cover this kind of functionality.