AngularJS - 带有指令的模块化表单 [英] AngularJS - Modular forms with directives

查看:20
本文介绍了AngularJS - 带有指令的模块化表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最初在这里问了这个问题,但我想我领先了并使它比实际情况更复杂,所以我在这里用更清晰的措辞重新提问.

I originally asked this question here, but I think I got ahead of myself and made it more complicated than it really is, so I'm re-asking it here with a bit clearer wording.

如何使用指令和可重复使用的参数创建可重复使用的表单小部件?像这样:

How do you create re-usable form widgets with directives and re-useable parameters? Like this:

<form>
<special-input label-text="A Special Input" bind-to="data.special"></special-input>
<special-input label-text="Specialer" bind-to="data.moreSpecial"></special-input>
</form>

指令模板似乎不允许对 ng-model 进行插值.

Directive templates don't seem to allow interpolation on ng-model.

此外,例如,您能否对表单行为进行模块化和参数化,以便您可以使用标准的 POST 操作?

Furthermore, can you modularize and parameterize form behavior so that you can have standard POST actions, for example?

我已经根据我的实验回答了下面的问题,但我暂时不会接受它,因为我对 Angular 非常陌生,并且想听听其他人的意见.

I've answer the question below based on my experimentation, but I'll hold off from accepting it for a while, since I am very new to Angular and would like to hear from others.

推荐答案

Angular 开箱即用,带有改进标签 此处记录. 基本上它以控制器的形式围绕表单及其中的所有标签创建一个范围.所以你这样做:

Angular comes out of the box with an improve tag that is documented here. Basically it creates a scope in the form of a controller around the form and all of the tags within it. So you do this:

<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
    <input name="firstInput" ng-model="data.first">
    <input name="secondInput" ng-model="data.second">
    <button ng-click="submit()">Submit</button>
</form>
</body>

JS:

var app = angular.app('TestApp', []);
app.controller('FormCtrl', function($scope) {
    $scope.submit = function() {
        // Form submit logic here
        console.log("Submitting the form");
        console.log($scope);
    }
})

这为表单创建了一个范围,因为表单标签包含 ng-controller 标签.在范围内,testForm 是表单的 javascript 对象,testForm.firstInput 是第一个输入的 javascript 对象.看起来这些对象也有一些可用的验证功能,在这里查看文档.

This creates a scope for the form, since the form tag contains the ng-controller tag. Within the scope, testForm is the javascript object for the form, and testForm.firstInput is the javascript object for the first input. It looks like these objects also have some validation functionality available, see docs here.

表单上的数据将作为 FormCtrl 作用域中的对象数据提供,键为first"和second",您可以在控制器中定义处理该对象的方法.

The data on the form will be available as an object data in the FormCtrl scope, with keys "first" and "second", and you can define methods in the controller that work on that.

你也可以使用同一个FormCtrl放置多个表单,而且Angular好像会为每个表单创建新的实例,所以你不必担心表单会污染彼此的数据.

You can also put multiple forms using the same FormCtrl, and it seems like Angular will create new instances for each form, so you don't have to worry about forms polluting each other's data.

现在假设我们有某种在指令中实现的复杂输入或小部件.本示例使用两个选择框来显示一个州的所有城市.您必须先选择一个州,然后它会查询该州的城市并填充第二个选择框.

Now lets suppose that we have some sort of complex input or widget that is implemented in a directive. This example uses two select boxes to display all cities in a state. You have to first select a state, then it'll query for the cities in that state and populate the second select box.

app.directive('citySelect', function() {
    return {
        replace: true,
        template: '<div><select ng-change="getCities()" ng-options="s.name for s in states"></select>' +
                  '<select ng-model="data.selectedCity" ng-options="c.name for c in cities"></select>',
        controller: function($scope) {
            // Omitting the logic for getCities(), but it'd go here
        }
    };
})

然后您可以将其粘贴到表单标签中,它就会起作用.因为指令没有定义作用域,它只会附加到 FormCtrl 的作用域.

Then you can just stick it into the form tag, and it'll work. Because the directive doesn't define a scope, it'll just attach to the scope of the FormCtrl.

<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
    <input name="firstInput" ng-model="data.first">
    <input name="secondInput" ng-model="data.second">
    <div city-select></div>
    <button ng-click="submit()">Submit</button>
</form>
</body>

参数化指令

所以显然这确实有效:

scope: {someParameter: "="},
template: '<div><select ng-model="someParameter"></select></div>'

您只需在没有卷曲的情况下进行操作,它就会绑定.我的猜测是父作用域绑定到子作用域中的 someParameter,然后选择绑定到子作用域中的 somParameter.

You simply do it without the curlies, and it'll bind. My guess is that the parent scope is binding to someParameter in the child scope, and the select is then binding to somParameter in the child scope.

因此,不需要在链接函数中手动编译以下所有内容.

So all of this below about manually compiling in the link function is not necessary.

======

但问题在于我的 citySelect 指令有一个硬编码的 ng-model 绑定,所以如果我创建了某种通用小部件,我不能在一个表单中使用多个.不幸的是,这似乎不起作用:

But the problem with this is that my citySelect directive has a hard coded ng-model binding, so if I created some sort of generic widget, I couldn't use more than one of it in a form. Unfortunately this does not seem to work:

scope: {someParameter: "="},
template: '<div><select ng-model="{{ someParameter }}"></select></div>'

我让它起作用的唯一方法是在链接函数中手动构建 DOM 元素,但我不确定这是否可取.我很感激任何人对此实施的评论:

The only way that I have gotten this to work is to build the DOM element manually in a linking function, but I'm not sure if this is advisable. I would appreciate comments from anyone about this implementation:

<body ng-app="TestApp">
<form ng-controller="FormCtrl" name="testForm">
    <input name="firstInput" ng-model="data.first">
    <input name="secondInput" ng-model="data.second">
    <div city-select bind-to="data.homeCity"></div>
    <div city-select bind-to="data.workCity"></div>
    <button ng-click="submit()">Submit</button>
</form>
</body>

app.directive('citySelect', function($compile) {
    return {
        replace: true,
        template: '<div></div>',
        controller: function($scope) {
            // Omitting the logic for getCities(), but it'd go here
        }
        link: function(scope, iElem, iAttrs) {
            var html = '<div><select ng-bind="' + iAttrs['bindTo'] + '"></div>';
            iElem.replaceWith($compile(html)(scope));
        }
    };
})

在表单中混入参数

由于为每个表单创建了单独的 FormCtrl 实例,您可以重用 FormCtrl 中的许多功能.但是您也可以在表单标签上使用其他指令来添加参数或分解功能.例如:

Mixing in parameters on the form

Since separate instances of FormCtrl are created for each form, you can reuse a lot of the functionality in FormCtrl. But you can also use additional directives on a form tag to add parameters or break apart functionality. For example:

<form ng-controller="FormCtrl" name="testForm" post-form post-path="/path/to/resource/">

app.directive('postForm', function() {
    return {
        controller: function($scope) {
            $scope.post = function() {
                // Some generic POST behavior
            };
        },
        link: function(scope, iElem, iAttr) {
            scope.postPath = iAttr['postPath'];
        },
    };
});

表单的作用域将合并来自 FormCtrl 和 postForm 的作用域,以便所有内容都可以访问.在我的实验中,似乎 FormCtrl 优先,所以如果在 FormCtrl 和 postForm 中都定义了类似 $scope.submit() 的东西,FormCtrl 将优先(我认为),也许这是异步加载的竞争条件,我不知道.

The form's scope will then combine the scope from FormCtrl and postForm, so that everything is accessible. In my experimentation, it seems like the FormCtrl takes precedence, so if something like $scope.submit() is defined in both FormCtrl and postForm, FormCtrl's will take precedence (I think), maybe this is a race condition from asynchronous loading, I don't know.

除了使用 ng-controller,我认为你也可以在 mixin 指令 (postForm) 上使用 scope:true,或者更安全的是,scope: {}.

Instead of using ng-controller, I think you can also use scope:true on the mixin directive (postForm), or perhaps more safely, scope: {}.

这篇关于AngularJS - 带有指令的模块化表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆