admin管理员组

文章数量:1279187

I'm having a problem trying to grasp why two way data binding is't working in my custom directive?

The codez:

Directive code:

.directive('invoiceFilter', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: '_invoice-filter.tpl.html',
        scope: {
            selectedItem: '=',
            selectedItemChange: '&'
        },
        link: function(scope) {

            scope.items = {
                all: 'Show all invoices',
                draft: 'Show drafts only',
                open: 'Show open invoices',
                paid: 'Show paid invoices'
            };

            scope.raiseSelectedItemChange = function (key) {


                alert('Selected item in directive: ' + key + " (which seems to work!)");

                scope.selectedItem = key;
                scope.selectedItemChange();

            };

        }
    };
});

Directive template

<div class="btn-group dropdown">
    <button class="btn dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
        {{ items[selectedItem || 'open' ] }}
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
        <li ng-repeat="(key, value) in items">
            <a href="javascript:void(0)" ng-click="raiseSelectedItemChange(key)">{{ value }}</a>
        </li>
    </ul>
</div>

As you can see I'm just adding some data to the scope (in the link function) and relying on the behavior of ng-repeat and ng-click to raise an event/callback when an item is selected. The alert correctly displays the selected item.

But when I start using the directive like this:

HTML

  <body ng-controller="MainController">
    <h1>Hello Plunker!</h1>
    <invoice-filter selected-item="filter" selected-item-change="filterChange()"></invoice-filter>
  </body>

Controller

    .controller('MainController', function($scope) {

        $scope.filter = "all";

        $scope.filterChange = function() {

          alert("Selected item in controller: " + $scope.filter + " (does not work, databinding problem???)");

        };

    })

The $scope.filter value never gets updated with the item I selected in the directive, even though I specified '=' on the directive scope which to my understanding should enable two way data binding, right?

What am I missing here?

Plunk playground

Here's a plunkr with the setup described above, so you can verify that it doesn't work :o/

Thanks to anyone who can help!

I'm having a problem trying to grasp why two way data binding is't working in my custom directive?

The codez:

Directive code:

.directive('invoiceFilter', function () {
    return {
        restrict: 'E',
        replace: true,
        templateUrl: '_invoice-filter.tpl.html',
        scope: {
            selectedItem: '=',
            selectedItemChange: '&'
        },
        link: function(scope) {

            scope.items = {
                all: 'Show all invoices',
                draft: 'Show drafts only',
                open: 'Show open invoices',
                paid: 'Show paid invoices'
            };

            scope.raiseSelectedItemChange = function (key) {


                alert('Selected item in directive: ' + key + " (which seems to work!)");

                scope.selectedItem = key;
                scope.selectedItemChange();

            };

        }
    };
});

Directive template

<div class="btn-group dropdown">
    <button class="btn dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown">
        {{ items[selectedItem || 'open' ] }}
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu" role="menu" aria-labelledby="dropdownMenu1">
        <li ng-repeat="(key, value) in items">
            <a href="javascript:void(0)" ng-click="raiseSelectedItemChange(key)">{{ value }}</a>
        </li>
    </ul>
</div>

As you can see I'm just adding some data to the scope (in the link function) and relying on the behavior of ng-repeat and ng-click to raise an event/callback when an item is selected. The alert correctly displays the selected item.

But when I start using the directive like this:

HTML

  <body ng-controller="MainController">
    <h1>Hello Plunker!</h1>
    <invoice-filter selected-item="filter" selected-item-change="filterChange()"></invoice-filter>
  </body>

Controller

    .controller('MainController', function($scope) {

        $scope.filter = "all";

        $scope.filterChange = function() {

          alert("Selected item in controller: " + $scope.filter + " (does not work, databinding problem???)");

        };

    })

The $scope.filter value never gets updated with the item I selected in the directive, even though I specified '=' on the directive scope which to my understanding should enable two way data binding, right?

What am I missing here?

Plunk playground

Here's a plunkr with the setup described above, so you can verify that it doesn't work :o/

Thanks to anyone who can help!

Share Improve this question edited Sep 28, 2018 at 6:41 Prashant Pokhriyal 3,8374 gold badges31 silver badges41 bronze badges asked Jun 2, 2014 at 10:58 DaveDave 431 silver badge4 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 10

The two-way binding works, but happens on the next cycle. That's why when you reproduce it again, the value of the last cycle is shown. This is because AngularJS has no chance to run its data binding inbetween the line where you set the value and the line where you call the callback. JavaScript, in that sense, doesn't allow intervention, yet.

Changing scope.selectedItemChange(); to $timeout(scope.selectedItemChange); is an easy fix (don't forget to inject $timeout), by forcing the callback to be called on the next cycle.

I had implemented something similar and resolved it slightly shorter version:

just add

scope.$watch();

after

scope.selectedItem = key;

And Angular will resolve by himself how and what to do.

本文标签: javascriptAngularJSTwo Way Data Binding in a Custom Directive Not WorkingStack Overflow