{"action":"created","issue":{"url":"https://api.github.com/repos/cipchk/ng-alain/issues/498","repository_url":"https://api.github.com/repos/cipchk/ng-alain","labels_url":"https://api.github.com/repos/cipchk/ng-alain/issues/498/labels{/name}","comments_url":"https://api.github.com/repos/cipchk/ng-alain/issues/498/comments","events_url":"https://api.github.com/repos/cipchk/ng-alain/issues/498/events","html_url":"https://github.com/cipchk/ng-alain/issues/498","id":330147654,"node_id":"MDU6SXNzdWUzMzAxNDc2NTQ=","number":498,"title":"feat(abc:simple-form): 简化HTML模板表单的运用","user":{"login":"cipchk","id":2987467,"node_id":"MDQ6VXNlcjI5ODc0Njc=","avatar_url":"https://avatars3.githubusercontent.com/u/2987467?v=4","gravatar_id":"","url":"https://api.github.com/users/cipchk","html_url":"https://github.com/cipchk","followers_url":"https://api.github.com/users/cipchk/followers","following_url":"https://api.github.com/users/cipchk/following{/other_user}","gists_url":"https://api.github.com/users/cipchk/gists{/gist_id}","starred_url":"https://api.github.com/users/cipchk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cipchk/subscriptions","organizations_url":"https://api.github.com/users/cipchk/orgs","repos_url":"https://api.github.com/users/cipchk/repos","events_url":"https://api.github.com/users/cipchk/events{/privacy}","received_events_url":"https://api.github.com/users/cipchk/received_events","type":"User","site_admin":false},"labels":[{"id":760543677,"node_id":"MDU6TGFiZWw3NjA1NDM2Nzc=","url":"https://api.github.com/repos/cipchk/ng-alain/labels/Discussion","name":"Discussion","color":"ce16a6","default":false},{"id":756535766,"node_id":"MDU6TGFiZWw3NTY1MzU3NjY=","url":"https://api.github.com/repos/cipchk/ng-alain/labels/feature","name":"feature","color":"0e8a16","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/cipchk/ng-alain/milestones/6","html_url":"https://github.com/cipchk/ng-alain/milestone/6","labels_url":"https://api.github.com/repos/cipchk/ng-alain/milestones/6/labels","id":3351204,"node_id":"MDk6TWlsZXN0b25lMzM1MTIwNA==","number":6,"title":"1.1.0","description":"","creator":{"login":"cipchk","id":2987467,"node_id":"MDQ6VXNlcjI5ODc0Njc=","avatar_url":"https://avatars3.githubusercontent.com/u/2987467?v=4","gravatar_id":"","url":"https://api.github.com/users/cipchk","html_url":"https://github.com/cipchk","followers_url":"https://api.github.com/users/cipchk/followers","following_url":"https://api.github.com/users/cipchk/following{/other_user}","gists_url":"https://api.github.com/users/cipchk/gists{/gist_id}","starred_url":"https://api.github.com/users/cipchk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cipchk/subscriptions","organizations_url":"https://api.github.com/users/cipchk/orgs","repos_url":"https://api.github.com/users/cipchk/repos","events_url":"https://api.github.com/users/cipchk/events{/privacy}","received_events_url":"https://api.github.com/users/cipchk/received_events","type":"User","site_admin":false},"open_issues":6,"closed_issues":0,"state":"open","created_at":"2018-05-16T09:23:31Z","updated_at":"2018-06-10T03:38:10Z","due_on":null,"closed_at":null},"comments":5,"created_at":"2018-06-07T07:23:07Z","updated_at":"2018-06-11T04:32:06Z","closed_at":null,"author_association":"OWNER","body":"## 前述\r\n\r\n在 ng-alain 中使用表单有三种方式：\r\n\r\n- @delon/form 动态表单\r\n- Angular 响应式表单\r\n- Angular HTML模板表单\r\n\r\n三者最大的区别在于可测试性和代码量由高到低。而现在的探讨的是后两者，一个表单需要呈现若干元素：\r\n\r\n![form-input](https://user-images.githubusercontent.com/2987467/41083020-b7f9ad08-6a62-11e8-854e-0dd2cd60a478.png)\r\n> 上图为 `@delon/form` 动态表单的实现细节\r\n\r\n在动态表单中非常容易实现，而对于后两者的实现唯一共同之处：大量HTML支持。\r\n\r\n```html\r\n<nz-form-item>\r\n    <nz-form-label [nzSpan]=\"8\" nzRequired>方法</nz-form-label>\r\n    <nz-form-control [nzSpan]=\"16\">\r\n        <input nz-input formControlName=\"method\" name=\"method\" maxlength=\"30\" required>\r\n        <nz-form-explain *ngIf=\"validateForm.get('note').dirty && validateForm.get('note').errors\">Please input your username!</nz-form-explain>\r\n    </nz-form-control>\r\n</nz-form-item>\r\n```\r\n\r\n> 响应式表单也略同。\r\n\r\n而如果我们希望一行两列表单元素，这太常见，则：\r\n\r\n```html\r\n<nz-row [nzGutter]=\"24\">\r\n    <nz-col [nzSpan]=\"12\">\r\n        <nz-form-item nzFlex>\r\n            <nz-form-label [nzSpan]=\"8\" nzRequired>方法</nz-form-label>\r\n            <nz-form-control style=\"flex: 1 0 auto;\">\r\n                <input nz-input formControlName=\"method\" name=\"method\" maxlength=\"30\" required>\r\n                <nz-form-explain *ngIf=\"validateForm.get('note').dirty && validateForm.get('note').errors\">Please input your username!</nz-form-explain>\r\n            </nz-form-control>\r\n        </nz-form-item>\r\n    </nz-col>\r\n    <nz-col [nzSpan]=\"12\">\r\n        <nz-form-item nzFlex>\r\n            <nz-form-label [nzSpan]=\"8\" nzRequired>名称</nz-form-label>\r\n            <nz-form-control style=\"flex: 1 0 auto;\">\r\n                <input nz-input formControlName=\"name\" name=\"name\" maxlength=\"30\" required>\r\n                <nz-form-explain *ngIf=\"validateForm.get('note').dirty && validateForm.get('note').errors\">Please input your username!</nz-form-explain>\r\n            </nz-form-control>\r\n        </nz-form-item>\r\n    </nz-col>\r\n</nz-row>\r\n```\r\n\r\n对于 ng-alain 而言，动态表单可以解决大部分场景，我们也希望尽可能的使用它们，然而事实还是需要在一些场合里使用Angular表单。\r\n\r\n这对于选择而言依然需要大量的HTML，ng-zorro-antd 默认使用文本边框红色来表示错误。\r\n\r\n同时若你希望更详细的错误反馈还需要维护 `nz-form-explain` 组件，而维护这个节点是非常麻烦的，一个用户名的错误反馈文本包括：\r\n\r\n- 用户名必填\r\n- 用户名最多5至15个字符\r\n- 用户名只能由字母、数字组合\r\n- 用户名已经存在\r\n\r\n你可能需要维护四个节点，当然情况下你只需要维护一到二个。这对于我们中后台而已依然很蛋疼，是否应该思考一下，有些表单元素是否真的是必要的呢？\r\n\r\n比如这里的错误文本视觉、布局，尝试把一行两列的表单变成：\r\n\r\n```html\r\n<nz-row [nzGutter]=\"24\">\r\n    <nz-col [nzSpan]=\"12\">\r\n        <simple-form-item term=\"方法\">\r\n          <input nz-input formControlName=\"method\" name=\"method\" maxlength=\"30\" required>\r\n        </simple-form-item>\r\n    </nz-col>\r\n    <nz-col [nzSpan]=\"12\">\r\n        <simple-form-item term=\"名称\">\r\n          <input nz-input formControlName=\"name\" name=\"method\" maxlength=\"30\" required>\r\n        </simple-form-item>\r\n    </nz-col>\r\n</nz-row>\r\n```\r\n\r\n我们依然还需要维护布局，然而就中台而言布局应该是**绝大部分**是等同固定的，于是：\r\n\r\n```html\r\n<simple-form-item term=\"方法\">\r\n  <input nz-input formControlName=\"method\" name=\"method\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n<simple-form-item term=\"名称\">\r\n  <input nz-input formControlName=\"name\" name=\"name\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n```\r\n\r\n视乎还需要一些特殊的情况，我们可以利用 `col=\"1\"` 来表示占1整列（antd的栅格系统是 `24` 列，`col` 的默认值为 `2` 时），比如：\r\n\r\n```html\r\n<simple-form-item term=\"方法\">\r\n  <input nz-input formControlName=\"method\" name=\"method\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n<simple-form-item term=\"名称\">\r\n  <input nz-input formControlName=\"name\" name=\"name\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n<simple-form-item term=\"描述\" col=\"1\">\r\n  <textarea nz-input formControlName=\"remark\" name=\"remark\">\r\n</simple-form-item>\r\n```\r\n\r\n假如你把响应式的代码也放弃了，则变成这样子：\r\n\r\n```html\r\n<simple-form-item term=\"方法\">\r\n  <input nz-input [(ngModel)]=\"method\" name=\"method\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n<simple-form-item term=\"名称\">\r\n  <input nz-input [(ngModel)]=\"name\" name=\"name\" maxlength=\"30\" required>\r\n</simple-form-item>\r\n<simple-form-item term=\"描述\" col=\"1\">\r\n  <textarea nz-input [(ngModel)]=\"remark\" name=\"remark\">\r\n</simple-form-item>\r\n```\r\n\r\n## 总结\r\n\r\n`simple-form-item` 将主动放弃一些东西，而转向一些开发效率上极致。假如这样的组件，你怎么看？"},"comment":{"url":"https://api.github.com/repos/cipchk/ng-alain/issues/comments/396119574","html_url":"https://github.com/cipchk/ng-alain/issues/498#issuecomment-396119574","issue_url":"https://api.github.com/repos/cipchk/ng-alain/issues/498","id":396119574,"node_id":"MDEyOklzc3VlQ29tbWVudDM5NjExOTU3NA==","user":{"login":"mango-csl","id":29364830,"node_id":"MDQ6VXNlcjI5MzY0ODMw","avatar_url":"https://avatars0.githubusercontent.com/u/29364830?v=4","gravatar_id":"","url":"https://api.github.com/users/mango-csl","html_url":"https://github.com/mango-csl","followers_url":"https://api.github.com/users/mango-csl/followers","following_url":"https://api.github.com/users/mango-csl/following{/other_user}","gists_url":"https://api.github.com/users/mango-csl/gists{/gist_id}","starred_url":"https://api.github.com/users/mango-csl/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mango-csl/subscriptions","organizations_url":"https://api.github.com/users/mango-csl/orgs","repos_url":"https://api.github.com/users/mango-csl/repos","events_url":"https://api.github.com/users/mango-csl/events{/privacy}","received_events_url":"https://api.github.com/users/mango-csl/received_events","type":"User","site_admin":false},"created_at":"2018-06-11T04:32:06Z","updated_at":"2018-06-11T04:32:06Z","author_association":"NONE","body":"一直有个疑问，formControl作用体现在哪里，其对自定义验证规则的复用，也很捉急。后来封装了一个基于rxjs的动态form组件，对表单涉及到的元素进行组件编写，支持自定义规则的复用和扩展，感觉用的还好，暂不支持自定义组件。`https://github.com/mango-csl/primeng-form-builder`"}}
{"actor":{"display_login":"mango-csl"}}