在AngularJS中控制器和指令之间的共享范围

问题描述:

我已经创建了一个指令来包装一个jQuery插件,并且我将一个用于插件的配置对象从控制器传递给指令。 (作品)在AngularJS中控制器和指令之间的共享范围

在配置对象是我想调用一个事件的回调。 (作品)

在回调中,我想修改控制器的$ scope的一个属性,其中不起作用。 Angular没有意识到由于某种原因该属性发生了变化,这导致我相信回调中的$范围与控制器的$范围不同。我的问题是我不知道为什么。

任何人都可以指向正确的方向吗?


Click here for Fiddle


app.js

var app = angular.module('app', []) 
    .directive('datepicker', function() { 
     return { 
      restrict: 'A', 
      link: function (scope, element, attrs) { 
       // Uncommenting the line below causes 
       // the "date changed!" text to appear, 
       // as I expect it would. 
       // scope.dateChanged = true; 

       var dateInput = angular.element('.datepicker') 

       dateInput.datepicker(scope.datepickerOpts); 

       // The datepicker fires a changeDate event 
       // when a date is chosen. I want to execute the 
       // callback defined in a controller. 
       // --- 
       // PROBLEM: 
       // Angular does not recognize that $scope.dateChanged 
       // is changed in the callback. The view does not update. 
       dateInput.bind('changeDate', scope.onDateChange); 
      } 
     }; 
    }); 

var myModule = angular.module('myModule', ['app']) 
    .controller('MyCtrl', ['$scope', function ($scope) { 
     $scope.dateChanged = false; 

     $scope.datepickerOpts = { 
      autoclose: true, 
      format: 'mm-dd-yyyy' 
     }; 

     $scope.onDateChange = function() { 
      alert('onDateChange called!'); 

      // ------------------ 
      // PROBLEM AREA: 
      // This doesnt cause the "date changed!" text to show. 
      // ------------------ 
      $scope.dateChanged = true; 

      setTimeout(function() { 
       $scope.dateChanged = false; 
      }, 5000); 
     }; 
    }]); 

HTML

<div ng-controller="MyCtrl"> 
    <p ng-show="dateChanged">date changed!</p> 
    <input type="text" value="02-16-2012" class="datepicker" datepicker=""> 
</div> 

有在您的演示工作若干问题的范围。首先,在dateChange回调中,即使函数本身在控制器内声明,回调内的this的上下文仍是引导元素,因为它位于引导句柄内。

每当您从第三方代码中更改角度范围值时,角度需要使用$apply来了解它。通常最好将所有第三方范围保留在指令内。

更有说服力的是在输入上使用ng-model。然后使用$.watch更改模型。这有助于保持控制器内的所有代码在角度上下文中。在任何角度的应用程序难得没有任何形式的使用ng-model控制

<input type="text" class="datepicker" datepicker="" ng-model="myDate"> 

在指令:

dateInput.bind('changeDate',function(){ 
     scope.$apply(function(){ 
     scope[attrs.ngModel] = element.val() 
     }); 
}); 
在控制器

然后:

$scope.$watch('myDate',function(oldVal,newVal){ 
     if(oldVal !=newVal){ 
      /* since this code is in angular context will work for the hide/show now*/ 
      $scope.dateChanged=true; 
      $timeout(function(){ 
        $scope.dateChanged=false; 
       },5000); 
     }   
}); 

演示:http://jsfiddle.net/qxjck/10/

编辑如果要在页面中的多个元素上使用此伪指令,应该更改的另一项是删除var dateInput = angular.element('.datepicker')。在指令中使用的是多余的,其中element已经是link回调中的参数之一,并且是实例特定的。与element

+0

一个多想更换dateInput ...有几个角/引导是超级容易在GitHub上使用 – charlietfl 2013-03-25 02:23:58

+0

感谢设置我直UI指令项目。我立即用$ apply(我可以拥抱你)为它工作,但我想要做到这一点,所以我试图实现你展示的方法。我没有显示,但应该在我的演示中,我实际上使用* *标记来触发日期选择器。所选日期保存在'element.data('datepicker')。getDate()'中。我是AngularJS的新手,所以请原谅我,如果我错了,但ng模型是为表单元素。什么是合适的替代品? – simshaun 2013-03-25 03:32:06

+0

不像我使用jQuery Ui那样熟悉bootstrap datepicker。然而,不要在输入中使用'ng-model',可以硬编码变量以在控制器范围内更新,或者使用任何想要存储变量名称的自定义属性(例如,如果在页面的多个位置使用此属性)。遇到更多问题,请使用''标签实施创建更新版本。作为elemnt数据的价值来源很容易在指令中的'scope。$ apply'调用中修改。保持相同的'$ watch' methodlogy。 – charlietfl 2013-03-25 03:38:24

绑定到输入的changeDate事件似乎设置为在Angular框架之外触发。要显示该段落,请在将dateChanged设置为true后,致电$scope.$apply()。要在延迟之后隐藏段落,可以在传递给setTimeout的函数中再次使用$apply(),但是您可能会使用Angular的$timeout()代替避免进一步的麻烦。

Fiddle