[英]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. 这样,就无需在子指令实例上重复绑定。
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.