簡體   English   中英

角度雙向數據綁定隔離作用域指令,但屬性未定義?

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

您好,我想我不明白什么是雙向數據綁定。 首先是代碼:

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

“ =”是否意味着外部范圍的更改將由於數據綁定而傳播? 或不? 因為我獲取了一個$ resource,它當然是在獲取后定義的,但是“屬性”仍然是未定義的。 那怎么了?

編輯:所需的行為是<mup-stage-button>模板中的ng-class工作

編輯:朋克: https ://plnkr.co/edit/drXxyMpd2IOhXMWFj8LP ? p = preview

您缺少有關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就足夠了。

UPDATE

為避免在子指令上重復執行property="company.stage"綁定,並分別通過父指令和子指令的controller和link函數傳遞數據,應將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的引用放到child指令的作用域中:

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

並最終在child指令的視圖中對其進行訪問:

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

這樣,就無需在子指令實例上重復綁定。

Plunk已更新。

在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指令中此處不會更改。 因此,我們將ctrl引用分配給scope.btnCtrl即可。 子指令的模板:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM