Angular双向绑定失效了!

先贴上代码:

controller:

.controller('FoldController', ['$scope', function ($scope){
    $scope.isFolded = true;   //  标志是否折叠的状态
}])

directive:

.directive('fold', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {

            // 只要点击其中的内容,让其折叠回去
            element.on('click',function () {  
                scope.isFolded = true;
                element.slideUp();
                console.log(scope);             
            });

            // 折叠的函数                
            function toggleFold(isFold) {

                isFold ? element.slideUp() : element.slideDown();
            }       

            // 监视是否折叠,即controller里定义的标志
            scope.$watch(attrs.fold, function (isFold) {
                toggleFold(isFold);
            });
        }
    }
})

html:

<nav class="navbar navbar-default" ng-controller="FoldController">
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle"
             ng-click="isFolded=!isFolded">  
            //  主要是这里  点击后toggle折叠的标志

                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>

            <a href="#/index" class="navbar-brand">Index {{isFolded}}</a>
                                          // 为了方便测试,我将折叠表示显示出来
        </div>
                                           // 这里用directive控制
        <div class="navbar-collapse collapse" fold="isFolded">
            <ul class="navbar-nav nav">
                <li class="active"><a href="#/index">index</a></li>
                <li><a href="#/about">about</a></li>
                <li><a href="#/contact">contact</a></li>
                <li><a href="#/chatroom">chatroom</a></li>
            </ul>
        </div>

    </div>
</nav>  

效果:

折叠时

图片描述

未折叠时

图片描述

前提交代完毕,我的期望是:

在未折叠时通过点击折叠区域,让其折叠回去,同时改变scope.isFold折叠标志,让其恢复原状,

问题是:

其中会有一个bug,就是我修改了scope.isFold的值,并且验证了scope的值是被改变的,但是页面上依然是原值,即双向绑定失效,看下图

图片描述

从图上的显示看,折叠区域已经被折叠,下面输出的scope.isFold也是正常的true,但是页面顶端上的值却是false,我验证过dom元素,是对了,验证过controller和directive里的scope.isFold的值,是对了,唯独这个页面就是对的,这个情况发生的也没有规律,挺郁闷的,谁来给看看。。。

阅读 14.3k
4 个回答

在你的事件处理函数中 加入 $scope.$apply

 <div class="navbar-collapse collapse" fold ng-model="isFolded">
            <ul class="navbar-nav nav">
                <li class="active"><a href="#/index">index</a></li>
                <li><a href="#/about">about</a></li>
                <li><a href="#/contact">contact</a></li>
                <li><a href="#/chatroom">chatroom</a></li>
            </ul>
        </div>

js

.directive('fold', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function (scope, element, attrs) {

            // 只要点击其中的内容,让其折叠回去
            element.on('click',function () {  
                scope.isFolded = true;
                element.slideUp();
                scope.$digest();
                console.log(scope);             
            });
   .....
     scope.$watch('isFolded', function (isFold) {
                toggleFold(isFold);
            });

解决方案是:

在操作完dom元素,修改scope上的属性值后,scope.$apply更新视图

element.on('click', function() {
    pe.isFolded = !scope.isFolded;          
    element.slideUp();
    scope.$apply();
})

其实很多人有个误区, 就是还在link函数中使用 elemnet.on 这种事件监听,
为什么不用ngClick然后在link中写一个scope.click函数呢?

除非你用的第三方的jQuery插件

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏