AngularJS基于API响应动态创建(和绑定)表单元素

时间:2014-01-16 07:08:40

标签: json angularjs-directive angularjs-scope angularjs-ng-repeat angularjs-service

我正在尝试使用所有预定义的手机类型创建会员的表单。

Contact Form

我正在为会员和电话类型提出两个api请求。这就是我的意思:

首先请求会员提供信息:

    $scope.member = {
    // $scope.member is returned from an api call
        "name": "John Doe",
        "phones": [{
            "id": "Cell",
            "phone": "(651) 111-1899",
            "phone_unlisted": false
        }, {
            "id": "Work",
            "phone": "(555) 121-1212",
            "phone_unlisted": true
        }]
    };

获取手机类型的第二个请求:

    myApp.controller("phoneTypes", function ($scope) {
        // $scope.phoneTypes is returned from an api call
        $scope.phoneNames = [{
            "id": "Cell"
        }, {
            "id": "Cell 2"
        }, {
            "id": "Work"
        }, {
            "id": "Work 2"
        }];
    });

尝试创建此表单失败。

HTML -

<div ng-controller="memberInfo">
    <h3>{{member.name}}</h3>
    <form role="form" ng-controller="phoneTypes">
        <h4>Phones</h4>
        <div ng-repeat="phoneName in phoneNames" >
            <label>{{phoneName.id}}</label>

            //need to bind phone detail from $scope.member if exists otherwise leave blank
            <input type="text" ng-model="member.phones.phone" />
            unlisted: <input type="checkbox" ng-model="member.phones.phone_unlisted" />
        </div>
    </form>
</div>

我需要绑定每个匹配的手机类型的电话号码,否则请将输入字段留空。

这是http://jsfiddle.net/4nzg4/

我已经完成了各种教程和帖子,但我无法解决这个问题。我是AngularJS的新手,任何帮助都将不胜感激。

谢谢,

2 个答案:

答案 0 :(得分:1)

一种可能的解决方案 - 虽然我觉得不舒服但最好将phones数组重新映射到phones_object,其中密钥是手机的id。换句话说,在memberInfo控制器的末尾,您可以:

$scope.member.phones_object = {};
$scope.member.phones.forEach( function( phone ) {
    $scope.member.phones_object[ phone.id ] = phone;
} );

然后,在模板中,您使用该对象显示电话号码:

    <div ng-repeat="phoneName in phoneNames" >
        <label>{{phoneName.id}}</label>
        <input type="text" ng-model="member.phones_object[ phoneName.id ].phone" />
        unlisted: <input type="checkbox" ng-model="member.phones_object[ phoneName.id ].phone_unlisted" /> <br/>
    </div>

这会给你我think is the result you want

That gives you this result.

不幸的是,会破坏Angular的双向绑定,至少会破坏原始的$scope.members.phones数据。如果需要,您可以使用$watch来保持数据同步,或者在准备好向API重新提交数据时将其同步备份,具体取决于您的应用程序。

答案 1 :(得分:1)

另一种不会立即破坏双向绑定但又有其自身缺点的方法是直接将缺少的手机类型添加到$scope.member。这是对现有代码的一个更大的修改。

首先,我们需要将控制器和模板组合到一个模板中:

<div ng-controller="memberInfo">
    <h3>{{member.name}}</h3>
    <form role="form">
        <h4>Phones</h4>
        <div ng-repeat="phone in member.phones" >
            <label>{{phone.id}}</label>
            <input type="text" ng-model="phone.phone" />
            unlisted: <input type="checkbox" ng-model="phone.phone_unlisted" /> <br/>
        </div>
    </form>
</div>

请注意,我们现在repeat直接通过member.phones。但是没有所有可用的手机类型?正确,但我们现在就解决这个问题。

var myApp = angular.module("myApp", []);

myApp.controller("memberInfo", function ($scope) {

    // $scope.member is returned from an api call
    $scope.member = {
        "name": "John Doe",
        "phones": [{
            "id": "Cell",
            "phone": "(651) 111-1899",
            "phone_unlisted": false
        }, {
            "id": "Work",
            "phone": "(555) 121-1212",
            "phone_unlisted": true
        }]
    };
    var phoneNames = [{
        "id": "Cell"
    }, {
        "id": "Cell 2"
    }, {
        "id": "Work"
    }, {
        "id": "Work 2"
    }];

    // make an array of the phone id's in $scope.member.phones
    var currently_used_names = $scope.member.phones.map( function( phone ) {
        return phone.id;
    } ); // returns [ "Cell", "Work" ]

    // add any phone names that weren't listed
    phoneNames.forEach( function( name ) {
        if ( currently_used_names.indexOf( name.id ) === -1 ) {
            $scope.member.phones.push( {
                "id": name.id,
                "phone": "",
                "phone_unlisted": false
            } );
        }
    } );
});

在这种情况下,我们会向$scope.member.phones添加任何需要使用某种默认模板列出的手机类型。

优势:保持双向绑定。

缺点:向$scope.member.phones添加“错误”数据,但可能很容易根据需要手动过滤掉。

这是a fiddle来演示。