嵌套指令中的AngularJS双向数据绑定

时间:2013-06-19 02:18:14

标签: javascript web-applications data-binding angularjs scope

如果您需要更多信息或希望我澄清任何内容,请告诉我。我已经尝试了很多不同的东西来解决这个问题,但还没有找到解决方案。

我对angularJS比较陌生,我正在尝试构建一个包含多层数据的应用程序。我有一些基本的用户信息存储在控制器PageController的正文范围内。然后我有一个设置表单,使用$ routeParams(带控制器SettingsController)加载,其中包含一些用于模板目的的自定义指令。由于指令是嵌套的,我使用transclusion来加载第一个指令。这一切似乎都很正常。

我的问题是我试图从最里面的指令中引用字段user.firstname,并希望使用双向数据绑定来允许对文本框所做的更改导致PageController范围的值更改为好。我知道很多这类问题是由在ng-model中使用原语引起的,但是我已经尝试将所有内容放在一个额外的对象中,这样我才能触发原型继承无济于事。我在这里做错了什么?

这是我的代码的JSFiddle,尽可能地删除以隔离问题。在这个例子中,如果我输入外部文本框,它直接在PageController范围内,它将修改内部文本框,直到该文本框被修改,连接断开。这看起来就像其他问题中描述的使用原语的问题,但我无法弄清楚问题出在哪里。

HTML:

<body class="event-listing" ng-app="app" ng-controller="PageController">
    <div class="listing-event-wrap">
        <input type="text" ng-model="user.firstname" />
        <div ng-controller="SettingsController">
            <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
                <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" value="user.firstname"></div>
            </section>
        </div>
    </div>
</body>

Angular Directives:

app.directive('formrow', function() {
return {
    scope: {
            label: "@label",
            type: "@type",
            value: "=value" 
    },
    replace: true,
    template: '<div class="form-row">' + 
            '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
            '<div class="form-entry" ng-switch on="type">' + 
                '<input type="text" ng-model="value" data-ng-switch-when="textInput" />' + 
            '</div>' + 
        '</div>'
}
});
app.directive('block', function() {
return {
    scope: {
            title: "@title",
            description: "@description" 
    },
    transclude: true,
    replace: true,
    template: '<div class="page-block">' +
            '<h2 data-ng-show="title">{{title}}</h2>' + 
            '<p class="form-description" data-ng-show="description">{{description}}</p>' + 
            '<div class="block-inside" data-ng-transclude></div>' + 
            '</div>'
}
});

角度控制器:

app.controller("PageController", function($scope) {
    $scope.user = {
        firstname: "John"
    };
});
app.controller("SettingsController", function($scope) {
    $scope.data = {
        updateInfo: {
            title: "Update Your Information",
            description: "A description here",
            labels: {
                firstname: "First Name"
            }
        }
    }
});

3 个答案:

答案 0 :(得分:11)

我很抱歉以前的代码。请改为尝试:http://jsfiddle.net/CxNc2/2/

我现在正在传递对象+指向内部正确值的指针,而不是传递实际值。我在这里添加了'refobject':

<body class="event-listing" ng-app="app" ng-controller="PageController">
    <div class="listing-event-wrap">
        <input type="text" ng-model="user.firstname" />
        <div ng-controller="SettingsController">
            <section block title="{{data.updateInfo.title}}" description="{{data.updateInfo.description}}">
                <div formrow label="{{data.updateInfo.labels.firstname}}" type="textInput" refobj='user' value="firstname"></div>
            </section>
        </div>
    </div>
</body>

我在这里添加了refobj +值:

app.directive('formrow', function() {
    return {
        scope: {
            label: "@label",
            type: "@type",
            value: "@value",
            refobj: "="
        },
        replace: true,
        template: '<div class="form-row">' + 
            '<div class="form-label" data-ng-show="label">{{label}}</div>' + 
            '<div class="form-entry" ng-switch on="type">' + 
        '<input type="text" ng-model="refobj[value]" data-ng-switch-when="textInput" />' + 
            '</div>' + 
        '</div>'
    }

答案 1 :(得分:8)

由于指令中的文本框使用原语而不是对象作为其模型(ng-model="value"而不是ng-model="someobj.somevalue"),因此仅在本地范围创建其模型,而父模型无法访问它。

修复方法是使用 dot rule 作为对象属性来定义指令文本框模型:

ng-model="value.firstname"

然后将整个user对象传递给指令,而不仅仅是原始属性:

<div formrow ... value="user"></div>

Here is a demo

答案 2 :(得分:0)

问题是由ng-switch引起的,来自git的文档Understanding scope

  

ng-switch范围继承的工作方式与ng-include类似。所以如果你需要的话   双向数据绑定到父作用域中的基元,使用$ parent或   将模型更改为对象,然后绑定到该属性   宾语。这将避免子范围隐藏/遮蔽父范围   属性。

所以如果你在文本框中输入一些文字。 下面的代码将针对ng-switch范围执行。

$scope.value="the text you typed"

因此,它不会查询原型链来搜索value。这会为ng-switch范围创建一个新属性。

如何作证?

如果您将value更改为$parent.value。一切都会好起来的。因为在基元类型的ng-switch中(如果没有点,angularjs会将value识别为基本类型)$parent将引用formrow指令范围。

尝试删除ng-switch或按照文档说的那样删除。问题就会消失。

更重要的是,该文档建议我们在应用双向绑定时始终使用点.来引用模型。

如果我说错了。请帮助纠正我并使其正确。谢谢。