angular-schema-form 自动表单生成

基本用法

通过bower安装之后,将schemaForm模块载入到模块定义中,fuse中安装第三方包需要在app/core/core.module.js中声明。

然后在controller里面,将schema、form、model属性赋给$scope,schema定义了数据结构,form定义了UI,model绑定了用户的输入。

angular.module('myModule', ['schemaForm'])
       .controller('FormController', function($scope) {
  $scope.schema = {
    type: "object",
    properties: {
      name: {
        type: "string",
        minLength: 2,
        title: "Name",
        description: "Name or alias" 
      },
      title: {
        type: "string",
        enum: ['dr','jr','sir','mrs','mr','NaN','dj']
      }
    },
    "required": ["name"]   // 定义强制字段
  };   // 表单字段定义

  $scope.form = [
    {
      key: "name",
      validationMessage: {
        200: 'Seriously? Value {{value}} totally shorter than {{schema.minLength}}, which is NOT OK.',
        302: "This field is like, uh, required?"
      }
    },
    "title",
    {
      type: "submit",
      title: "Save"
    }
  ];   // 定义表单各个域以及他们的行为(错误信息、提交按钮等)

  $scope.model = {};  // 用户的输入绑定到这里
});

然后在模板中,通过ng-controller载入,使用sf-schema、sf-form、sf-model指令。

<div ng-controller="FormController">
    <form sf-schema="schema" sf-form="form" sf-model="model"></form>
</div>

sf-schema指令不一定要在form标签中,实际上可以放在一个div中,比如需要有一个自己编写的按钮或表单域。

 

处理提交

Schema Form并不在意你怎么处理你的数据,处理提交最推荐的方式是使用ng-submit指令,同时建议用name属性从而可以在FormController中访问到它,并且验证合法性。

你可以通过broadcast一个事件(schemaFormValidate)来强制执行校验。

$scope.onSubmit = function(form) {
  // First we broadcast an event so all fields validate themselves
  $scope.$broadcast('schemaFormValidate');

  // Then we check if the form is valid
  if (form.$valid) {
    // ... do whatever you need to do with your data.
  }
}

关于$scope.$broadcast的用法参考stackoverflow

 

表单更新

Schema Form监听sf-form和sf-schema,当他们改变的时候会重画整个表单,但也不是完全改变(……不知道文档这里在讲什么)

如果想要手动更新表单,可以调用schemaFormRedraw事件。

function Ctrl($scope) {
  $scope.removeLastField = function() {
    $scope.form.pop()
    $scope.$broadcast('schemaFormRedraw')
  }
}

 

全局属性

Schema Form通过sf-options来设定全局属性,sf-options应该和sf-schema放在一起。它接收一个对象,有以下属性和取值。

属性 类型 描述
supressPropertyTitles boolean 默认下没有设置schema的title时,会用它的名字作为title,将本属性设为true会取消这个默认行为
formDefaults object 一个对象,定义到所有的表单项中
validationMessage object or function  
setSchemaDefaults boolean  
destroyStrategy string  
pristine Object {errors, success}  
validateOnRender boolean  

formDefaults属性最常用的是设置ngModelOptions,以下设置会使表单的每项都带上一个属性:ng-model-options="form.ngModelOptions"

<div ng-controller="FormController">
    <form sf-schema="schema"
          sf-form="form"
          sf-model="model"
          sf-options="{ formDefaults: { ngModelOptions: { updateOn: 'blur' } }}"></form>
</div>

关于ng-model-options:常用于将“model与用户输入实时同步”改为“model在用户输入完(blur之后)再同步”。参看文档

 

校验信息

Schema Form使用tv4来校验表单。以下几个方法可以改变默认的校验信息:

  1. 改变sfErrorMessages的默认值(通过其provider),这会将校验信息设置到sf-schema的所有实例中。
  2. 用全局属性validationMessage
  3. 用表单域属性validationMessage

如果一个定义好的验证错误代码在表单域属性中找不到,schema form会找全局属性,如果没有则用它的默认值(不知道文档在说什么……)

错误的类型是通过匹配tv4的错误码

信息插入

通过value、shcema等变量可以读取到用户输入的值,以及schema中定义的值,从而使得错误信息动态变化。(error:错误类型码,这个应该也常用,比如说定义好一个错误信息的数组errorMessage[],通过errorMessage[error]就能读取对应的错误信息。)

$scope.form = [
  {
    key: "name",
    validationMessage: {
      200: 'Seriously? Value {{value}} totally shorter than {{schema.minLength}}, which is NOT OK.',
      302: "This field is like, uh, required?"
    }
  },
  "title",
  {
    type: "submit",
    title: "Save"
  }
];

*这里的{{value}}并不能正常显示用户的输入,待解决。

 

自定义校验

有一些需要后端协助的校验。Schema Form允许我们注入任意的校验信息到任意的表单域中。

这是通过schemaForm.error事件开始,然后在表单域的key结束。它需要两个参数,第一个是错误码/错误名,第二个是校验信息/布尔值。使用的是$scope.$broadcast。

例子:在后台校验发现用户名重复时,调用以下语句可以让表单不合法,并显示信息:

$scope.$broadcast('schemaForm.error.name','usernameAlreadyTaken','The username is already taken');

如果后台校验发现用户名可以使用,调用以下语句可以让表单合法,这时第二个参数要为true:

$scope.$broadcast('schemaForm.error.name','usernameAlreadyTaken',true);

使用ngModelController

另一个校验表单的方法是使用ngModelController,Schema Form可以将ngModelController暴露在一个表单域中,给一个定义了表单的函数(……又不知道在说什么)。或者你可以用一个shorthand,就是通过加$validators和$asyncValidators。

我的简单理解:就是$validators和$asyncValidators都是用函数来进行校验,区别是一个是同步的一个是异步的,下面是$asyncValidators的例子:

$scope.form = [
  {
    key: 'name',
    placeholder: 'Anything but "Bob"',
    $asyncValidators: {
      'async': function(name) {
        var deferred = $q.defer();
        $timeout(function(){
          if (angular.isString(name) && name.toLowerCase().indexOf('bob') !== -1) {
            deferred.reject();
          } else {
            deferred.resolve();
          }
        }, 1500);
        return deferred.promise;
      }
    },
    validationMessage: {
      'async': "Wooohoo thats not an OK name!"
    }
  },
  ....
];

上面的代码会在输入name表单域时,经过1.5秒后校验用户的输入是不是bob(忽略大小写)

 

表单的默认schema

比较推荐的做法是将表单元素的UI和验证分开,但是如果确实需要在schema中定义表单元素的UI,则可以通过x-schema-form属性来进行设置。x-schema-form需要是一个对象。

{
  "type": "object",
  "properties": {
    "comment": {
      "type": "string",
      "title": "Comment",
      "x-schema-form": {
        "type": "textarea",
        "placeholder": "Don't hold back"
      }
    }
  }
}

默认表单type

在schema定义表单的type,对应生成的表单的类型如下表。

 

Form定义

form的定义有三种形式:

  1. 星号"*",代表整个schema都使用默认形式
  2. 一个字符串,标识属性名:"name"
  3. 一个对象,定义了表单的各种属性(placeholder、校验信息等等):{ key: "name" , ... }

另外在$scope.form中可以重写表单域的顺序和它的type。

$scope.schema = {
  "type": "object",
  "properties": {
    "surname":     { "type": "string" },
    "firstname":   { "type": "string" },
  }
};

$scope.form = [
  "firstname",
  {
    key: "surname",
    type: "select",
    titleMap: [
      { value: "Andersson", name: "Andersson" },
      { value: "Johansson", name: "Johansson" },
      { value: "other", name: "Something else..."}
    ]
  }
];

 

posted @ 2016-04-26 13:57  寄生蠕虫  阅读(2921)  评论(0编辑  收藏  举报