简体   繁体   English

AngularJS中的动态表单

[英]Dynamic form in AngularJS

I'm developing a CMS for a customer, it's all based on AngularJS with its controllers, views, services, etc. 我正在为客户开发CMS,它全部基于AngularJS及其控制器,视图,服务等。

What I need is a pattern where a dynamically loaded script injects some data in an existing scope . 我需要的是一种模式,其中动态加载的脚本在现有范围内注入一些数据

Ok, in human words: I have a form managed by a controller . 好吧,用人类的话来说: 我有一个由控制器管理的表单 This form has several preset fields. 该表格有几个预设字段。 These fields are managed by an array of the scope, something like: 这些字段由范围数组管理,例如:

$scope.fields = [
  { type: "text", name="first_name" },
  { type: "text", name="last_name" },
  { type: "email", name="email" }
];

The view prints dynamically the fields (ie it's a scaffolding). 该视图动态打印字段(即是脚手架)。

When the customer log into the application I check if in his profile he has a custom script to load, if so the application appends a javascript to the DOM, the javascript file name is equal to the username of the logged user. 当客户登录到应用程序时,我检查他的个人资料中是否有要加载的自定义脚本,如果是,则应用程序将javascript附加到DOM,则javascript文件名等于登录用户的用户名。

So, if the user is called " darko " and he has a custom script enabled, the application append this file to the DOM: 因此,如果用户被称为“ darko ”,并且启用了自定义脚本,则应用程序将此文件附加到DOM:

/js/customers/darko.js /js/customers/darko.js

Let's say that darko has further fields to show (and save) inside the form , how can I do that? 假设darko在表单中还有其他字段要显示(并保存) ,我该怎么做? I'd need to hook the controller so I can have access to its scope and then inject my fields. 我需要钩住控制器,以便可以访问其作用域,然后注入字段。 Something like: 就像是:

var $scope = getUserFormScope();//some magic....
$scope.fields.push({ type: "text", name="skype" });

However, The form with further fields is just an example, what I really need, more generally, is a way to "hook controllers" and have access to theirs scopes. 但是,带有更多字段的表单仅是示例,更确切地说,我真正需要的是一种“挂钩控制器”并可以访问其作用域的方法。

Any idea? 任何想法?

SOLUTION

I've finally used the method suggested by marfarma. 我终于使用了marfarma建议的方法。 The custom script contains one or more partial controllers named with the same name of the controller they want to extend prefixed by Custom word, then I extend my controllers with these partial controllers. 自定义脚本包含一个或多个部分控制器,这些控制器的名称与要扩展的自定义字词前缀相同,然后使用这些部分控制器扩展我的控制器。 For example, my app has a controller named PageController, inside this controller I check if a CustomPageController exists: 例如,我的应用程序有一个名为PageController的控制器,在此控制器内,我检查CustomPageController是否存在:

if (typeof CustomPageController == 'function') {
    angular.extend(this, CustomPageController($scope));
}

if so, I extend the main controller with the custom one. 如果是这样,我将使用自定义控制器扩展主控制器。

Here is a general way to "hook controllers" and have access to their scopes - mixin your hook code via angular.extend. 这是“钩子控制器”并可以访问其作用域的一种通用方法-通过angular.extend混合钩子代码。

function CustomUserController($scope) {
    // contents of this hook controller is up to you

    var _this = this;

    // Mixin instance properties.
    this.vocalization = getValue('vocalization',$scope.user);
    this.runSpeed = getValue('runSpeed'        ,$scope.user);

    // Mixin instance methods.
    this.vocalize = function () {
        console.log(this.vocalization);
    };

    // Mixin scope properties.
    $scope.color = color;

    // Mixin scope methods.
    $scope.run = function(){
        console.log("run speed: " + _this.runSpeed );
    };
}

function PageController($scope) {

    var _this = this;
    $scope.user; // this should be the current user obj, with key for custom script lookup

    // Mixin Custom Script into Controller.
    if (userService.hasCustomScript($scope.user)) {
        angular.extend(this, new CustomUserController($scope));
    }
}

As for your specific example, one way to insert arbitrary fields into a form is to build it dynamically. 对于您的特定示例,将任意字段插入表单的一种方法是动态构建它。 I use a schema form directive that might work for your situation. 我使用了一种可能适合您情况的架构表单指令。 Given a schema that defines the model properties, and an array that specified the items their order of inclusion, the directive lays out the form. 给定一个定义模型属性的模式,以及一个指定项目包含顺序的数组,该指令对表单进行布局。

For example (see also this working plunker, incl. add'l features ): 例如(另请参见此工作的插件,包括add'l features ):

<form class="form-inline" name="form" novalidate role="form">
    <div class="row-fluid clearfix">
        <h2>Sample Form</h2>
    </div>
    <div class="row-fluid clearfix">
        <hr> 
        <div class="span12">
            <fieldset class="span6">
                <schema-form-fields
                    fields="side1Fields"
                    model="model"
                    schema="modelSchema"
                    data="requestResult"
                    schema-list="schema">
                </schema-form-fields>
            </fieldset>
            <fieldset class="span6">
                <schema-form-fields
                    fields="side2Fields"
                    model="model"
                    schema="modelSchema"
                    data="requestResult"
                    schema-list="schema">
                </schema-form-fields>
            </fieldset>
        </div>
    </div>
    <div class="row-fluid clearfix">
        <button
            class="btn btn-primary span2 offset10"
            type="submit">
            Submit
        </button>
    </div>
</form>
// example controller with dynamic form
app.controller('HomeCtrl', ['$scope', 'schema', 'requestResult', 'dataService',
    function($scope, schema, requestResult, dataService) {

        $scope.modelSchema = schema.product;          
        $scope.model = {
            factoryDate: '20160506'
        };

        // field name arrays - one array per column in sample layout
        // insert elements into these and form should re-render
        // may require explicit watch to trigger update
        $scope.side1Fields = [
            'productName',
            'factoryDate'
        ];

        $scope.side2Fields = [
            'productType',
            'timeValue'
        ];  

        // ....  other controller code    
    }
]);
// example schema
app.value('schema', {
    "product": {
        "type": "object",
        "title": "Product Schema",
        "properties": {
            "productType": {
                "type": "string",
                "title": "Product Type",
                "showLabel": true,
                "tooltip": "Product classification",
                "readonly": false,
                "required": true,
                "class": "custom-select",
                "enum": ['Bike', 'Car', 'Airplane', 'Glider', 'Stilts']
            },
            "productName": {
                "title": "Product Name",
                "showLabel": true,
                "type": "string",
                "tooltip": "A more descriptive name for the modeled structure.",
                "readonly": false,
                "required": true
            },
            "factoryDate": {
                "title": "Factory Date",
                "type": "string",
                "showLabel": true,
                "control": "date",
                "dateFormat": "yyyymmdd",  // TODO format as provided 
                "tooltip": "Date of manufacture.",
                "dateOptions": {
                    autoclose: true
                },
                "readonly": false,
                "required": true
            },
            "timeValue": {
                "title": "Time (HHMM)",
                "showLabel": true,
                "type": "string",
                "pattern": "([0-1]{1}[0-9]{1}|20|21|22|23)[0-5]{1}[0-9]{1}",
                "timeFormat": "hhmm",  // TODO format as provided 
                "tooltip": "Time entry.",
                "readonly": false,
                "required": true,
            }
        }
    }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM