//main controller
angular.module('myApp')
.controller('mainCtrl', function ($scope){
    $scope.loadResults = function (){
        console.log($scope.searchFilter);
    };
});

// directive
angular.module('myApp')
.directive('customSearch', function () {
    return {
        scope: {
            searchModel: '=ngModel',
            searchChange: '&ngChange',
        },
        require: 'ngModel',
        template: '<input type="text" ng-model="searchModel" ng-change="searchChange()"/>',
        restrict: 'E'
    };
});

// html
<custom-search ng-model="searchFilter" ng-change="loadResults()"></custom-search>

这是一个简化的指令来说明。当我输入内容时,我期望console.log中的loadResults完全注销我已经输入的内容。它实际上在后面记录了一个字符,因为loadResults在主 Controller 中的searchFilter var从指令接收新值之前运行。但是,在指令内部登录后,一切都会按预期进行。为什么会这样呢?

我的解决方案

在我的简单示例中了解了ngChange发生了什么之后,我意识到我实际传递的ngModel是一个对象,该对象的属性在不断变化,而我又在改变我的实际问题,这使我的实际问题更加复杂了。我正在使用带有该指令的表单验证作为输入之一。我发现在指令中使用$ timeout和$ eval解决了我所有的问题:
//main controller
angular.module('myApp')
.controller('mainCtrl', function ($scope){
    $scope.loadResults = function (){
        console.log($scope.searchFilter);
    };
});

// directive
angular.module('myApp')
.directive('customSearch', function ($timeout) {
    return {
        scope: {
            searchModel: '=ngModel'
        },
        require: 'ngModel',
        template: '<input type="text" ng-model="searchModel.subProp" ng-change="valueChange()"/>',
        restrict: 'E',
        link: function ($scope, $element, $attrs, ngModel)
        {
            $scope.valueChange = function()
            {
                $timeout(function()
                {
                    if ($attrs.ngChange) $scope.$parent.$eval($attrs.ngChange);
                }, 0);
            };
        }
    };
});

// html
<custom-search ng-model="searchFilter" ng-change="loadResults()"></custom-search>

最佳答案

您在标题中回答了自己的问题!观看'='而未观看'&'

  • Angular 外的某个地方:

    输入 View 值更改
  • 下一个摘要周期:
    ng-model值更改并触发ng-change()
    ng-change添加一个$ viewChangeListener,并且被称为同一循环。
    看:
    ngModel.js#L714ngChange.js实现。

    那时$scope.searchFilter尚未更新。 Console.log的旧值
  • 下一个摘要周期:searchFilter通过数据绑定(bind)更新。

  • 更新:仅当POC需要一个额外的周期才能传播该值时,您可以执行以下操作。请参阅其他anwser(@NewDev,以获取更清洁的方法)。
    .controller('mainCtrl', function ($scope, $timeout){
        $scope.loadResults = function (){
            $timeout(function(){
               console.log($scope.searchFilter);
            });
        };
    });
    

    10-08 15:49