【问题标题】:AngularJS: Parent scope is not updated in directive (with isolated scope) two way bindingAngularJS:父范围未在指令中更新(具有隔离范围)双向绑定
【发布时间】:2014-04-28 18:02:43
【问题描述】:

我有一个具有隔离范围的指令,其值通过两种方式绑定到父范围。我正在调用一个更改父范围中的值的方法,但更改未应用于我的指令中。(不会触发双向绑定)。这个问题非常相似:

AngularJS: Parent scope not updated in directive (with isolated scope) two way binding

但我没有更改指令中的值,而是仅在父范围内更改它。我阅读了解决方案,在第五点中说:

The watch() created by the isolated scope checks whether it's value for the bi-directional binding is in sync with the parent's value. If it isn't  the parent's value is copied to the isolated scope.

这意味着当我的父值更改为 2 时,会触发监视。它检查父值和指令值是否相同 - 如果不是,则复制到指令值。好的,但我的指令值仍然是 1 ...我错过了什么?

html:

<div data-ng-app="testApp">
    <div data-ng-controller="testCtrl">
        <strong>{{myValue}}</strong>
        <span data-test-directive data-parent-item="myValue" 
            data-parent-update="update()"></span>
    </div>
</div>

js:

var testApp = angular.module('testApp', []);

testApp.directive('testDirective', function ($timeout) {
    return {
        scope: {
            key: '=parentItem',
            parentUpdate: '&'
        },
        replace: true,
        template:
            '<button data-ng-click="lock()">Lock</button>' +
            '</div>',
        controller: function ($scope, $element, $attrs) {
            $scope.lock = function () {
                console.log('directive :', $scope.key);

                 $scope.parentUpdate();
                 //$timeout($scope.parentUpdate); // would work.

                 // expecting the value to be 2, but it is 1
                 console.log('directive :', $scope.key);
            };
        }
    };
});

testApp.controller('testCtrl', function ($scope) {
    $scope.myValue = '1';
    $scope.update = function () {
        // Expecting local variable k, or $scope.pkey to have been
        // updated by calls in the directive's scope.
        console.log('CTRL:', $scope.myValue);
        $scope.myValue = "2";
        console.log('CTRL:', $scope.myValue);
    };
});

Fiddle

【问题讨论】:

标签: angularjs


【解决方案1】:

在控制器中更改$scope.myValue 后使用$scope.$apply(),例如:

testApp.controller('testCtrl', function ($scope) {
    $scope.myValue = '1';
    $scope.update = function () {
        // Expecting local variable k, or $scope.pkey to have been
        // updated by calls in the directive's scope.
        console.log('CTRL:', $scope.myValue);
        $scope.myValue = "2";
        $scope.$apply();
        console.log('CTRL:', $scope.myValue);
    };
});

【讨论】:

  • 好的,我知道有办法让它工作,但我的问题是为什么这是必要的。这就是为什么这被称为双向绑定?
  • 双向数据绑定是 AngularJS 范围内的东西。在这里,您正在对指令进行更改,这超出了 Angular JS 本机代码结构的范围。因此,为了反映您需要使用的更改 $scope.$apply()
  • 它给了我$apply already in progress 错误。在上面给出的 jsfiddle 链接中尝试了同样的方法。
【解决方案2】:

答案使用 $scope.$apply() 是完全错误的。

我看到的更新指令范围的唯一方法是这样的:

angular.module('app')
.directive('navbar', function () {
    return {
        templateUrl: '../../views/navbar.html',
        replace: 'true',
        restrict: 'E',
        scope: {
            email: '='
        },
        link: function (scope, elem, attrs) {
            scope.$on('userLoggedIn', function (event, args) {
                scope.email = args.email;
            });
            scope.$on('userLoggedOut', function (event) {
                scope.email = false;
                console.log(newValue);

            });

        }
    }
});

并像这样在控制器中发出事件:

$rootScope.$broadcast('userLoggedIn', user);

这感觉就像一个 hack 我希望角度大师可以看到这篇文章并提供更好的答案,但因为它是公认的答案甚至不起作用,只是给出错误 $digest 已经在进行中

【讨论】:

  • 如果我在 10 处添加指令,那么会发生什么.. 你知道吗??? 10 次回调将被调用。甚至给一个发射或广播
  • 根据我的经验,在某些情况下,如果您发送的对象很大,您将无法使用它,因为它会报错。
【解决方案3】:

像接受的答案一样使用 $apply() 可能会导致各种错误和潜在的性能下降。设置广播和诸如此类的工作很多。我发现了一个简单的解决方法,即使用标准超时在下一个周期触发事件(由于超时,这将立即发生)。像这样围绕 parentUpdate() 调用:

$timeout(function() {
    $scope.parentUpdate();
});

非常适合我。 (注:未指定时默认超时时间为0ms)

【讨论】:

  • 之所以有效,是因为在 Angular 的 $timeout 函数结束时,它调用了 $apply()。它几乎等同于setTimout(function() { /* yourCallback() */ $rootScope.apply(); }, 0),只是它做了一些我不太了解的额外内容。
  • 执行if (!$scope.$$phase) { $scope.$apply() } 也可以避免$apply already in progress error,但无论如何,这并不能很好地解释问题发生的原因。需要更清晰的答案。
  • 谁能解释为什么这实际上必须在下一个周期或当前不进行?
【解决方案4】:

大多数人忘记的一件事是,您不能只用对象表示法声明一个孤立的范围,并期望绑定父范围的属性。这些绑定只有在声明了绑定“魔术”的属性时才有效。查看更多信息:

https://umur.io/angularjs-directives-using-isolated-scope-with-attributes/

【讨论】:

    【解决方案5】:

    不要使用$scope.$apply(),而是尝试使用$scope.$applyAsync();

    【讨论】:

    • 解释一下为什么建议使用 $applyAsync 而不是 $apply 会更有用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多