I'm in the process of customizing validation messages. It's working fine using the messageTemplates property. However it uses %displayName% to render the name of the property and I can't find out how to override this value ? Is there anyway to do that ?
I was wanting to do this also but I wanted to use the [DisplayName] attribute from my EF model. I couldn't find anyone that had an example of doing this so after I found a way I thought I would share.
First, I extended the metadata returned from my BreezeController:
[HttpGet]
public string Metadata()
{
// Extend metadata with extra attributes
JObject metadata = JObject.Parse(contextProvider.Metadata());
string nameSpace = metadata["schema"]["namespace"].ToString();
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
Type t = Type.GetType(nameSpace + "." + typeName);
foreach (var prop in t.GetProperties())
{
foreach (var attr in prop.CustomAttributes)
{
string name = attr.GetType().Name;
foreach (var p in entityType["property"])
{
if (prop.Name == p["name"].ToString()) {
if (attr.AttributeType.Name == "DisplayNameAttribute") {
DisplayNameAttribute a = (DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute));
p["displayName"] = a.DisplayName;
break;
}
}
}
}
}
}
return metadata.ToString();
}
Then I added a little javascript after the metadata load to poke the display names from the augmented metadata where Breeze wants to find them.
manager.fetchMetadata().then(function (md) {
angular.forEach(md.schema.entityType, function (et) {
var etype = manager.metadataStore.getEntityType(et.name);
angular.forEach(et.property, function (p) {
var prop = etype.getProperty(p.name);
prop.displayName = p.displayName;
});
});
console.log("starting app");
angular.bootstrap($("#app"), ["app"]);
});
I'm using angular so if you aren't you can ignore the angular stuff and probably get the idea. This seems to work rather nicely. It should be pretty easy to extend this to other model attributes as well like the RegularExpression validation attribute. I'll probably work on that next.
FYI, some of this code is not optimized and could probably be refactored, prettied up a bit but I just got it working and thought I would share. If anyone has any suggestions of a better way let me know. Hopefully Breeze will allow extending the metadata in a more supported way in the future. This does seem like a bit of a hack.
This is not YET well documented but you can simply set the 'displayName' property on any dataProperty and this will override the autogenerated display name and will be used for all validation messages for this property. So
var custType = myEntityManager.metadataStore.getEntityType("Customer");
var dp = custType.getProperty("companyName");
dp.displayName = "My custom display name";
Also, please see "Customize the message templates" at the bottom of this page: Breeze Validation
Following jpcoder request for suggestions, here goes my slightly improved server portion:
JObject metadata = JObject.Parse(contextProvider.Metadata());
string nameSpace = metadata["schema"]["namespace"].ToString();
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
Type t = Type.GetType(nameSpace + "." + typeName);
IEnumerable<JToken> metaProps = null;
if (entityType["property"].Type == JTokenType.Object)
metaProps = new[] { entityType["property"] };
else
metaProps = entityType["property"].AsEnumerable();
var props = from p in metaProps
let pname = p["name"].ToString()
let prop = t.GetProperties().SingleOrDefault(prop => prop.Name == pname)
where prop != null
from attr in prop.CustomAttributes
where attr.AttributeType.Name == "DisplayNameAttribute"
select new
{
Prop = p,
DisplayName = ((DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute))).DisplayName
};
foreach (var p in props)
p.Prop["displayName"] = p.DisplayName;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With