breezejs: overriding displayname

橙三吉。 提交于 2019-12-12 08:06:25

问题


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 ?


回答1:


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




回答2:


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.




回答3:


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;
}



回答4:


Looking at http://www.breezejs.com/sites/all/apidocs/files/a40_entityMetadata.js.html#l1452,

could this be improved by renaming the existing "name" value to nameOnServer (to satisfy the getDataProperty call) and inserting the DisplayNameAttribute value as "name"?




回答5:


A necessary change to the server code is that, if your model classes are in different assemblies, you cannot use

Type t = Type.GetType(nameSpace + "." + typeName);

You need the namespace per type (which is in the metadata), and (I think) to use BuildManager to locate the appropriate types in different assemblies. The mapping from cSpaceOSpaceMapping might be achieved more elegantly, but I didn't have time to research the different json formatting options.

JObject metadata = JObject.Parse(UnitOfWork.Metadata());
string EFNameSpace = metadata["schema"]["namespace"].ToString();
string typeNameSpaces = metadata["schema"]["cSpaceOSpaceMapping"].ToString();
typeNameSpaces = "{" + typeNameSpaces.Replace("],[", "]|[").Replace("[", "").Replace("]", "").Replace(",", ":").Replace("|", ",") + "}";
        JObject jTypeNameSpaces = JObject.Parse(typeNameSpaces);

        foreach (var entityType in metadata["schema"]["entityType"])
        {
            string typeName = entityType["name"].ToString();
            string defaultTypeNameSpace = EFNameSpace + "." + typeName;
            string entityTypeNameSpace = jTypeNameSpaces[defaultTypeNameSpace].ToString();
            Type t = BuildManager.GetType(entityTypeNameSpace, false);

            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;
            }
        }



回答6:


        JObject metadata = JObject.Parse(this._context.Metadata());
        string EFNameSpace = metadata["schema"]["namespace"].ToString();
        string typeNameSpaces = metadata["schema"]["cSpaceOSpaceMapping"].ToString();
        typeNameSpaces = "{" + typeNameSpaces.Replace("],[", "]|[").Replace("[", "").Replace("]", "").Replace(",", ":").Replace("|", ",") + "}";
        JObject jTypeNameSpaces = JObject.Parse(typeNameSpaces);

        foreach (var entityType in metadata["schema"]["entityType"])
        {
            string typeName = entityType["name"].ToString();
            string defaultTypeNameSpace = EFNameSpace + "." + typeName;
            string entityTypeNameSpace = jTypeNameSpaces[defaultTypeNameSpace].ToString();
            Type t = BuildManager.GetType(entityTypeNameSpace, false);

            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 == "DisplayAttribute"
                        select new
                        {
                            Prop = p,
                            DisplayName = ((DisplayAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayAttribute))).Name
                        };
            foreach (var p in props)
            {
                p.Prop["displayName"] = p.DisplayName;
            }
        }

        return metadata.ToString();



回答7:


Improving jpcoder's answer ...

For me most of my DisplayName changes were to replace "PascalCaseFieldName" or "camelCaseFieldName" with "Upper Case Field Name". So rather than set every property DisplayName on the server, I applied a default function to set displayName.

End result was much less EF annotation required. My TypeScript is:

    manager.metadataStore.getEntityTypes().forEach(function (storeEntityType) {
        if (!(storeEntityType instanceof breeze.EntityType)) {
            throw new Error("loadExtendedMetadata found '" + storeEntityType
                + "' StructuralType that is not an EntityType (e.g. a ComplexType)");
        }

        var extEntityType = extendedMetadata.entitiesExtended.find((extendedEntityType) => {
            return extendedEntityType.shortName + ":#" + extendedEntityType.nameSpace === storeEntityType.name;
        });


        (storeEntityType as breeze.EntityType).getProperties().forEach((storeProperty) => {
            //Both NavigationProperty & DataProperty have displayName & nameOnServer properties
            var storeDataProperty = <breeze.DataProperty>storeProperty;

            var extProperty;
            if (extEntityType) {
                extProperty = extEntityType.propertiesExtented.find((extendedProperty) => {
                    return extendedProperty.name === storeDataProperty.nameOnServer;
                });
            }

            //Smart default: nameOnServer "PascalCaseFieldName" or "camelCaseFieldName" converted to "Upper Case Field Name"
            storeDataProperty.displayName = (extProperty && extProperty.displayName)
                || storeDataProperty.nameOnServer.replace(/^./, function (str) {
                    // first ensure the first character is uppercase
                    return str.toUpperCase();
                    // insert a space before all caps, remove first character (added space)
                }).replace(/([A-Z])/g, " $1").substring(1);
        });
    });


来源:https://stackoverflow.com/questions/16733251/breezejs-overriding-displayname

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!