3

我正在尝试使用 Angular-Formly 从一组 .NET 类开始构建动态表单。

我序列化了 json 中的类属性信息并将其返回给 Formly,但没有显示任何字段。

我遵循以下建议:How to load angular-formly vm.fields object from remote-generated json? 但似乎不适合我。

我的表单代码是:

<form ng-submit="vm.onSubmit()" novalidate>
   <formly-form model="vm.model" fields="vm.formFields">
      <button type="submit" class="btn btn-primary submit-button">Submit</button>
   </formly-form>
</form>

角码是:

<script>
    /* global angular */
    (function () {
        'use strict';

        var app = angular.module('formlyExample', ['formly', 'formlyBootstrap'], function config(formlyConfigProvider) {
            // set templates here
            //formlyConfigProvider.setType({
            //    name: 'custom',
            //    templateUrl: 'custom.html'
            //});
        });

        app.factory('User', function ($http) {
            return {
                getFields: getFields
            };

            function getFields() {
                return $http.post('TestFormly.aspx/LoadData', { headers: { 'Cache-Control': 'no-cache' } });
            }
        });

        app.controller('MainCtrl', function MainCtrl($scope, $http, User) {
            var vm = this;
            // funcation assignment
            vm.onSubmit = onSubmit;

            vm.loadingData = User.getFields().then(function (result) {
                vm.fields = JSON.parse(result.data.d);
                vm.originalFields = angular.copy(vm.fields);
            });

            vm.model = {
            };

            // function definition
            function onSubmit() {
                alert(JSON.stringify(vm.model), null, 2);
            }
        });
    })();
</script>

CSharp.Net 代码是:

    [WebMethod]
    public static string LoadData()
    {
        string retValue = null;

        List<FieldItem> m_fields = new List<FieldItem>();

        FieldItem item1 = new FieldItem();
        item1.key = "text";
        item1.type = "input";
        item1.templateOptions = new TemplateOptions() { label = "Text", placeholder = "Formly is terrific!" };

        FieldItem item2 = new FieldItem();
        item2.key = "story";
        item2.type = "textarea";
        item2.templateOptions = new TemplateOptions() { label = "Some sweet story", placeholder = "It allows you to build and maintain your forms with the ease of JavaScript :-)" };

        m_fields.Add(item1);
        m_fields.Add(item2);

        retValue = JsonConvert.SerializeObject(m_fields);

        return retValue;
    }

JSON结果是:

[
    {
        "key":"text",
        "type":"input",
        "templateOptions":{
            "label":"Text",
            "placeholder":"Formly is terrific!"
        }
    },
    {
        "key":"story",
        "type":"textarea",
        "templateOptions":{
            "label":"Some sweet story",
            "placeholder":"It allows you to build and maintain your forms with the ease of JavaScript :-)"
        }
   }
]

使用 firebug 调试我看到 JSON 正确传递到 vm.fields 但没有显示输入框,只有 Sumbit 按钮。

我注意到 Formly示例也没有显示这些字段。

你能帮我吗 ?

在此先感谢,朱塞佩。

4

2 回答 2

1

这是我快速破解的一个解决方案,作为我自己的概念证明。

基本上,FormlyModelBuilder 确实扫描了一个 ViewModel 类并构建了一个正式的字段模型。

示例使用

public IActionResult Index()
        {
            return Ok(new ViewModels.Account.FormlyModelBuilder<ViewModels.Account.RegisterViewModel>().JsonStringify(new ViewModels.Account.RegisterViewModel { Email = "test@test.com" }));
        }

改变这个

public class RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare ("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

进入这个

{
  "fields": [{
    "key": "Email",
    "type": "email",
    "templateOptions": {
      "isRequired": false,
      "label": "Email"
    },
    "expressionProperties": {
      "templateOptions.focus": "Email"
    }
  }, {
    "key": "Password",
    "type": "password",
    "templateOptions": {
      "isRequired": false,
      "label": "Password"
    },
    "expressionProperties": {}
  }, {
    "key": "ConfirmPassword",
    "type": "password",
    "templateOptions": {
      "label": "Confirm password"
    },
    "expressionProperties": {}
  }],
  "model": {
    "email": "test@test.com"
  },
  "expressionProperties": {}
}

源代码

public class FormlyModelBuilder<T>
    {
        internal T GetAttributeFrom<T>(object instance, string propertyName) where T : Attribute
        {
            var property = instance.GetType().GetProperty(propertyName);
            return GetAttributeFrom<T>(property);
        }
        internal T GetAttributeFrom<T>(PropertyInfo property) where T : Attribute
        {
            var attrType = typeof(T);
            T t = (T)property.GetCustomAttributes(attrType, false).FirstOrDefault();
            if (t == null)
            {
                var metaAttr = (MetadataTypeAttribute[])property.ReflectedType.GetCustomAttributes(typeof(MetadataTypeAttribute), true);
                if (metaAttr.Length > 0)
                {
                    foreach (MetadataTypeAttribute attr in metaAttr)
                    {
                        var subType = attr.MetadataClassType;
                        var pi = subType.GetField(property.Name);
                        if (pi != null)
                        {
                            t = (T)pi.GetCustomAttributes(attrType, false).FirstOrDefault();
                            return t;
                        }


                    }
                }

            }
            else
            {
                return t;
            }
            return null;
        }

        internal FormlyModel<T> Build(T dataModel)
        {
            if (dataModel == null) throw new ArgumentNullException(nameof(dataModel));
            //
            var modelType = typeof(T);
            var model = new FormlyModel<T>(dataModel);
            foreach (var property in modelType.GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.Public))
            {
                var type = GetAttributeFrom<DataTypeAttribute>(property);
                var field = new FormlyField(property.Name, GetInputTypeFromDataType(type?.DataType, property.PropertyType));
                model.AddField(field);
                //
                var display = GetAttributeFrom<DisplayAttribute>(property);
                field.TemplateOptions.Label = display?.Name;
                //
                var required = GetAttributeFrom<RequiredAttribute>(property);
                field.TemplateOptions.IsRequired = required?.AllowEmptyStrings;
                //

            }
            var focusField = model.Fields.First();
            focusField.ExpressionProperties["templateOptions.focus"] = focusField.Key;
            return model;
        }
        internal string JsonStringify(T dataModel)
        {
            if (dataModel == null) throw new ArgumentNullException(nameof(dataModel));
            //
            var dcr = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver();
            dcr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
            //
            return Newtonsoft.Json.JsonConvert.SerializeObject(Build(dataModel),
                new Newtonsoft.Json.JsonSerializerSettings
                {
                    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                    ContractResolver = dcr
                });
        }

        private string GetInputTypeFromDataType(DataType? dataType, Type propertyType)
        {
            if (dataType != null)
            {
                //
                switch (dataType)
                {
                    case DataType.Text:
                        return "input";
                    case DataType.Password:
                        return "password";
                    case DataType.EmailAddress:
                        return "email";
                    case DataType.Html:
                    case DataType.MultilineText:
                    case DataType.Custom:
                    case DataType.DateTime:
                    case DataType.Date:
                    case DataType.Time:
                    case DataType.Duration:
                    case DataType.PhoneNumber:
                    case DataType.Currency:
                    case DataType.Url:
                    case DataType.ImageUrl:
                    case DataType.CreditCard:
                    case DataType.PostalCode:
                    case DataType.Upload:
                    default:
                        break;
                }
            }
            switch (propertyType.Name)
            {
                case nameof(System.Boolean):
                    return "checkbox";
                default:
                    return "input";
            }
        }
    }
    internal class FormlyModel<T>
    {
        internal FormlyModel(T dataModel)
        {
            if (dataModel == null) throw new ArgumentNullException(nameof(dataModel));
            //
            this.Fields = new List<FormlyField>();
            this.Model = dataModel;
            this.ExpressionProperties = new Dictionary<string, string>();
        }

        internal IEnumerable<FormlyField> Fields { get; }
        internal T Model { get; }
        internal Dictionary<string, string> ExpressionProperties { get; }
        internal void AddField(FormlyField field)
        {
            if (field == null) new ArgumentNullException(nameof(field));
            //
            ((List<FormlyField>)this.Fields).Add(field);
        }
    }
    internal class FormlyField
    {
        internal FormlyField(string key, string type)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentNullException(nameof(key));
            if (string.IsNullOrWhiteSpace(type)) throw new ArgumentNullException(nameof(type));
            //
            TemplateOptions = new TemplateOptions();
            ExpressionProperties = new Dictionary<string, string>();
            Key = key;
            Type = type;
        }
        internal string Key { get; }
        internal string Type { get; }
        internal string HideExpression { get; set; }
        internal TemplateOptions TemplateOptions { get; }
        internal Dictionary<string, string> ExpressionProperties { get; }
    }
    internal class TemplateOptions
    {
        public bool? IsRequired { get; set; }
        public string Label { get; set; }
        public string Placeholder { get; set; }
    }
于 2016-01-09T23:38:50.137 回答
1

显然,示例中使用的 Angular-Formly (6.0.0-beta.1) 版本正在引发异常。我记得这是以前工作的。无论如何,我将其恢复为稳定版本并再次工作。

这是带有正式 json 的 jsbin,它应该可以正常工作:http: //jsbin.com/towozegiqu/edit

于 2015-08-28T12:06:22.483 回答