Javascript 更改值时未触发$watch

Javascript 更改值时未触发$watch,javascript,jquery,angularjs,Javascript,Jquery,Angularjs,对于何时在Angularjs中使用$apply,我有点困惑,我的困惑来自以下示例 这是我的设计: 1) 我制作了一个自定义指令“profile modal”,该指令具有属性“visible”,“visible”属性存储一个“profileShow”变量,该变量决定是否显示弹出框 2) 在该指令中,我双向绑定visible attrible,因为外部范围控制器将修改“profileShow”变量,同时该指令将修改“visible”属性以显示/隐藏该框 3) 当用户点击指定按钮时,控制器将修改“pr

对于何时在Angularjs中使用$apply,我有点困惑,我的困惑来自以下示例

这是我的设计:

1) 我制作了一个自定义指令“profile modal”,该指令具有属性“visible”,“visible”属性存储一个“profileShow”变量,该变量决定是否显示弹出框

2) 在该指令中,我双向绑定visible attrible,因为外部范围控制器将修改“profileShow”变量,同时该指令将修改“visible”属性以显示/隐藏该框

3) 当用户点击指定按钮时,控制器将修改“profileShow”选项,框将弹出

4) 当用户关闭引导框时,on hidden函数将更改属性“visible”,该属性触发$watch in指令关闭对话框

这是密码

<profile-modal visible="profileShow"></profile-modal>
<button type="button" class="btn btn-primary btn-sm" ng-click="addConfProfile()">
   <span class="glyphicon glyphicon-plus"></span> Add Profile
</button>

    define(['testConfig','bootstrap-dialog'],function(testConfig, BootstrapDialog){
    testConfig
        .controller('apConfCtrl', function($scope){
            $scope.profileShow = false;
            $scope.addConfProfile = function(){
                $scope.profileShow = !$scope.profileShow;
            };
        })
        .directive('profileModal',function(){
            return {
                restrict: 'E',
                templateUrl: 'templates/profile_add_dialog.html',
                replace: true,//replace the original profile modal dom
                scope:{
                    visible: '=',
                },
                link: function(scope, elm, attr){
                    //set modal title
                    scope.profileTitle = "Add Profile";
                    scope.$watch('visible', function(n,o){
                        console.log(n);
                        console.log(o);
                        if (n){
                            $(elm).modal('show');
                        }
                        else{
                            $(elm).modal('hide');
                        }
                    });

                    $(elm).on('hidden.bs.modal', function(){
                        scope.visible = false;
                        scope.$apply(); // >>Why this is necessary??
                        //console.log(scope.visible);
                    });

                }
            };
        });
});

添加配置文件
定义(['testConfig','bootstrap-dialog'],函数(testConfig,BootstrapDialog){
测试配置
.controller('apConfCtrl',函数($scope){
$scope.profileShow=false;
$scope.addConfProfile=函数(){
$scope.profileShow=!$scope.profileShow;
};
})
.directive('profileModal',function(){
返回{
限制:'E',
templateUrl:'templates/profile\u add\u dialog.html',
replace:true,//替换原始配置文件模式dom
范围:{
可见:“=”,
},
链接:功能(范围、elm、属性){
//设置模态标题
scope.profileTitle=“添加配置文件”;
范围:$watch('visible',功能(n,o){
控制台日志(n);
控制台日志(o);
如果(n){
$(elm.modal('show');
}
否则{
$(elm.modal('hide');
}
});
$(elm.on('hidden.bs.modal',function(){
scope.visible=false;
范围.$apply();/>为什么这是必要的??
//console.log(scope.visible);
});
}
};
});
});
但当实现时,我面临以下问题:第一次单击按钮,一切都按预期进行,框弹出,然后关闭框。在我第二次尝试打开盒子时,没有弹出任何内容。。。然后我再次尝试点击,它再次弹出

然后我发现主要的问题是,on hidden操作不会触发$watch函数来更改属性“visible”,但令人惊讶的是,当我尝试添加范围时,$apply在更改属性变量后,它会工作!我只是想知道为什么我必须这样做,Angularjs是否应该帮助监视变量“可见”,而不调用$apply


感谢任何帮助

Angular依靠一种称为“消化周期”的东西来获取任何更改。触发该摘要循环的是调用
$scope.$digest()
$scope.$apply()

对于大多数内置的角度指令,它们已经为您触发了一个摘要周期。例如,当检测到更改时,在摘要周期中执行监视侦听器函数,该函数在监视的表达式更改时执行


但是,对于任何不属于Angular的内容,例如发生的jQuery事件,您需要“告诉”Angular。这意味着自己调用
$scope.$apply()

还建议您在
$scope
的子对象内定义布尔值、数字或字符串属性(在您的示例中为“profileShow”),而不是直接将它们设置为
$scope
的属性。这种方法的原因是bool,数字和字符串按值传递,而数组和对象按引用传递。因此,angular不会为您调用
$digest
循环,即使您的属性发生更改,并且您必须手动调用
$apply()
方法。

非常感谢您的澄清,但仍然有一点不太明白,如何定义这是“jQuery”还是非jQuery?,我曾经认为Angular的代码(比如指令、控制器)所包装的东西属于Angular:(这是知道是否需要使用
$apply()的主要标志)
是指如果你做了任何不使用Angular服务的异步工作,比如
$http
$timeout
$interval
。这意味着
setTimeout()
,事件处理程序,
jQuery.ajax()
,等等。感谢你的明确解释