Angular双向数据绑定隔离范围指令但属性未定义?

时间:2016-06-04 21:15:58

标签: javascript angularjs

你好我想我不明白双向数据绑定是什么。首先是代码:

Simulation sim = new Simulation();

“=”是否意味着外部范围的变化会因数据绑定而传播?或不?因为我获取$资源,它当然是在获取它之后定义的,但是“属性”仍未定义。那有什么不对?

编辑:期望的行为是sim模板中的ng-class工作

编辑:plunker:https://plnkr.co/edit/drXxyMpd2IOhXMWFj8LP?p=preview

2 个答案:

答案 0 :(得分:2)

您遗漏了transclude选项的重要内容:包装内容绑定到 OUTER 范围,而不是指令的范围。

那么,这里是编译后范围绑定在你的案例中的样子:

<div ng-controller="CompanyDetailController">
    <mup-stage-buttons property="company.stage" action="setStage"> <-- even though the 'property' is bound correctly, it is not available below due to transclusion -->
        <span ng-transclude>
            {{company.stage}} <!-- CompanyDetailController $scope available here due to transclusion, 'property' is not available! -->

            <mup-stage-button property="company.stage" value="0"> 
                <!-- directive's scope here, binding to the outer scope's 'company.stage' can be used here -->
                {{property}} - {{value}} <!-- this will work -->
                <label ng-class="property === value ? 'active' : 'btn-on-hover' " class="btn {{btnClass}}" ng-click="changeStage(value)">
                    <div ng-transclude>
                        <!-- transcluded content here, bound to the CompanyDetailController $scope -->
                        not working ng-class 0
                    </div>
                </label>
            </mup-stage-button>
        </span>
    </mup-stage-buttons>
</div>

因此,要使代码正常工作(Plunk),仅将property映射到子指令的company.stage就足够了。

<强>更新

为了避免重复对子指令的property="company.stage"绑定并分别通过父指令和子指令的控制器和链接函数传递数据,您应该使用wrapping object作为范围属性,这样你就可以通过引用传递给那个对象了。对象范围的任何更改都将可用于子范围,因为它们将引用该对象,这称为dot notation

CompanyDetailController:

$scope.vars = {};
this.getCompany = function () {
  $scope.vars.company = $scope.company = {stage: 0}; 
};

然后将vars属性绑定到父指令的范围:

// ...
scope: {
    vars: '=',
},
controller: function($scope) {
    this.vars = $scope.vars;
}
// ...

然后将vars的引用放到子指令的范围:

// ...
link: function(scope, element, attrs, mupStageButtonsCtrl, transclude) {
    scope.vars = mupStageButtonsCtrl.vars;
}
// ...

最后可以在子指令的视图中访问它:

<label ng-class="vars.company.stage === value ? 'active' : 'btn-on-hover'">...</label>

这样就不需要在子指令实例上重复绑定了。

Plunk已更新。

答案 1 :(得分:0)

在javascript中

  

基元按值传递,对象通过“副本传递”   参考”。

使用$ watch的解决方案:

.directive('mupStageButtons', function() {
    return {
        transclude: true,
        template: '<span ng-transclude></span>',
        replace: true,
        scope: {
            property: "=",
            action: "="
        },
        controller: function($scope) {
            that = this;
            $scope.$watch('property', function(newValue){
                that.property = newValue;    
      /***Refresh this.property (normal assignment would only copy value, 
     it would not behave as a reference to desired transcluded property)***/
            });
            this.changeStage = $scope.action;
        },
    };
})
.directive('mupStageButton', function() {
    return {
        transclude: true,
        templateUrl: '/static/templates/directives/StageButton.html',
        require: '^^mupStageButtons',
        scope: {
            value: "=",
            btnClass: "@",
        },
        link: function(scope, element, attrs, mupStageButtonsCtrl, transclude) {
            scope.btnCtrl = mupStageButtonsCtrl;
            scope.changeStage = mupStageButtonsCtrl.changeStage;
        }
    };
})

$ watch旁边的一个重要部分也是链接功能:

scope.btnCtrl = mupStageButtonsCtrl;

我们无法做到

scope.property = mupStageButtonsCtrl.property;

因为它只是复制值,当它在ctrl中改变时,它在child指令中不会改变。 所以我们为scope.btnCtrl分配ctrl引用,它可以工作。 儿童指令的模板:

<label ng-class="btnCtrl.property === value ? 'active' : 'btn-on-hover' " class="btn {{btnClass}}" ng-click="changeStage(value)">
    <div ng-transclude></div>
</label>

现在我可以根据需要使用指令 - 只传递像company.stage这样的属性,这样指令就不需要知道属性名称(阶段)了。

<mup-stage-buttons property="company.stage" action="setStage">
    <mup-stage-button value="0" btn-class="btn-default-grey">
        Stage 0
    </mup-stage-button>
</mup-stage-buttons>