简体   繁体   English

角度双向数据绑定隔离作用域指令,但属性未定义?

[英]Angular two-way data binding isolate scope directive but property is undefined?

Hello I think I don't understand what two-way data binding is. 您好,我想我不明白什么是双向数据绑定。 First the code: 首先是代码:

.directive('mupStageButtons', function() {
    return {
        transclude: true,
        template: '<span ng-transclude></span>',
        replace: true,
        scope: {
            property: "=",
            action: "="
        },
        controller: function($scope) {
            console.log($scope); //I can see the property of $scope defined in console
            console.log($scope.property); //undefined
            this.property = $scope.property;
            this.changeStage = $scope.action; //anyway this is ok
        },
    };
})
.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.property = mupStageButtonsCtrl.property;
            scope.changeStage = mupStageButtonsCtrl.changeStage;
        }
    };
})

//html

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


//controller for that html ^^^

.controller('CompanyDetailController', function($scope, $stateParams, Company){
    Company.query ({
      id : $stateParams.companyId
    }, function (data) {
      $scope.company = new Company(data);
    });
}

//template for <mup-stage-button>

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

Does the "=" mean, that the change in outside scope will propagate thanks to data binding? “ =”是否意味着外部范围的更改将由于数据绑定而传播? Or not? 或不? Because I fetch a $resource and it is of course defined after the time it is fetched, but the "property" remains undefined. 因为我获取了一个$ resource,它当然是在获取后定义的,但是“属性”仍然是未定义的。 So what is wrong? 那怎么了?

EDIT: desired behavior is that the ng-class in the template for <mup-stage-button> works 编辑:所需的行为是<mup-stage-button>模板中的ng-class工作

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

You are missing an important thing about the transclude option: the wrapped content is bound to the OUTER scope rather than the directive's scope. 您缺少有关transclude选项的重要事项:包装的内容绑定到OUTER范围,而不是指令的范围。

So, here how the scope bindings will look in your case after compilation: 因此,在编译后的情况下,作用域绑定的外观如下:

<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>

So, to make your code work ( Plunk ) it would be enough to map the property to the company.stage on the child directive only. 因此,要使您的代码正常工作( Plunk ),仅在子指令上将property映射到company.stage就足够了。

UPDATE UPDATE

To avoid repetition of the property="company.stage" binding on the child directives and pass the data through the controller and link function of the parent and child directives respectively, you should use the wrapping object for you scope properties, so that you could pass the reference to that object through. 为避免在子指令上重复执行property="company.stage"绑定,并分别通过父指令和子指令的controller和link函数传递数据,应将wrapping object用作作用域属性,以便传递对该对象的引用。 Any changes to this object will be available to the child scopes as they will have a reference to that object, this is called the dot notation : 对该子对象的任何更改将对子作用域可用,因为它们将对该子对象进行引用,这称为dot notation

CompanyDetailController: CompanyDetailController:

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

then bind the vars property to the parent directive's scope: 然后将vars属性绑定到父指令的作用域:

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

then put the reference of vars to the child directive's scope: 然后将vars的引用放到child指令的作用域中:

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

and finally have access to it in the child directive's view: 并最终在child指令的视图中对其进行访问:

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

This way there is no need to repeat the bindings on the child directive instances. 这样,就无需在子指令实例上重复绑定。

Plunk is updated. Plunk已更新。

In javascript 在JavaScript中

Primitives are passed by value, Objects are passed by "copy of a reference". 基元按值传递,对象按“引用副本”传递。

Solution using $watch: 使用$ 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;
        }
    };
})

An important part besided the $watch is also this in link function: $ watch旁边的重要部分也是链接功能中的这个:

scope.btnCtrl = mupStageButtonsCtrl;

We could not do 我们做不到

scope.property = mupStageButtonsCtrl.property;

because it would just copy the value, and when it changed in the ctrl, it wouldn't change here in the child directive. 因为它只会复制该值,并且当它在ctrl中更改时,在child指令中此处不会更改。 So we assign ctrl reference to scope.btnCtrl and it works. 因此,我们将ctrl引用分配给scope.btnCtrl即可。 Template for child directive: 子指令的模板:

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

Now I can use the directives generically as I need - pass just the property like company.stage , so that the directive doesn't need to know the property name (stage). 现在,我可以根据需要通用地使用这些指令-仅传递诸如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>

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

相关问题 Angular指令将范围隔离到父绑定未定义 - Angular directive isolate scope to parent binding undefined 如何在没有*隔离范围的指令*中获得双向数据绑定? - How to get two way data binding in a directive *without* an isolate scope? Angular指令引发双向数据绑定 - Angular directive throws off two-way data binding 如果包含在另一个指令中的指令,我如何在隔离范围中添加双向数据绑定attr? - How can I add, in isolate scope, two way data binding attr in case of directive including in another directive? 在自定义指令的控制器中更新$ scope时,Angular.js双向绑定不起作用? - Angular.js two-way binding do not work when update the $scope in the controller of custom directive? 为什么在angularjs指令链接函数中未定义双向绑定? - why is two-way binding undefined in angularjs directive link function? Angular 中分离的双向数据绑定 - Separate two-way data binding in Angular angular指令不会使用控制器更新双向绑定 - angular directive won't update two-way binding with controller 角度指令,使用布尔型的双向数据绑定仅工作一次 - angular directive, two-way data binding with boolean works only once 隔离作用域双向绑定不会及时更新以调用操作 - Isolate scope two-way binding doesn't update in time for action to be invoked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM