【问题标题】:How to change AngularJS data outside the scope?如何在范围之外更改 AngularJS 数据?
【发布时间】:2013-07-13 10:27:32
【问题描述】:

经过数小时令人沮丧的搜索后,我觉得我需要在这里提交我的问题。如果之前以某种方式回答了这个问题,我提前道歉,但到目前为止我的搜索都没有帮助。所以这是我的问题:

我的 JavaScript 代码正在创建一个由 AngularJS 修改和监控的对象。在某些事件上(例如加载对象的先前设置),我希望从范围之外更改此对象的属性。问题是输入没有改变......

以下是我希望如何执行这些更改的示例:


HTML 代码:

<div ng-app="myApp" ng-controller="FirstCtrl">
<input type="number" ng-model="data.age">
<h1>{{data.age}}</h1>

<input type="button" value="Change to 20" ng-model="data" onclick="change()">

JavaScript 代码:

var person = {
    age: 16
};

// Create module
var myApp = angular.module('myApp', []);
myApp.factory('Data', function() {
    return person;
});

function FirstCtrl($scope, Data) {
    $scope.data = Data;
}

function change() {
    person.age = 20;
}

当我现在按下“更改为 20”按钮时,没有任何反应。如何通过change 函数修改此人的年龄?

【问题讨论】:

    标签: javascript angularjs input


    【解决方案1】:

    ⚠️ 警告:这个答案很旧,不反映最佳实践,并且可能与较新版本的 Angular 不兼容。

    MaxPRafferty 的回答是正确的——在作用域中使用函数通常是更好的方法——但还有另一种选择。您可以使用 angular.element(...).scope() 方法从不相关的 JavaScript 访问 Angular 范围。通过定位具有指定 ng-app 属性的元素,选择应用的顶级范围,类似于在您的点击处理程序中:

    function change() {
        var appElement = document.querySelector('[ng-app=myApp]');
        var $scope = angular.element(appElement).scope();
        $scope.$apply(function() {
            $scope.data.age = 20;
        });
    }
    

    试试in this Fiddle

    Shaunjust pointed out Angular 只会在 $digest() 调用期间处理任何“监视”或“绑定”。如果只是直接修改$scope 的属性,更改可能不会立即反映,并且可能会出现错误。

    要触发此操作,您可以调用$scope.$apply(),它将检查脏范围并更新正确绑定的任何内容。传递一个在 $scope.$apply 内部完成工作的函数也将允许 Angular 捕获任何异常。此行为在the documentation for Scope 中进行了解释。

    【讨论】:

    • 这很完美!先生非常感谢您。每当我在控制器外部更改对象的属性时,我都必须这样做。这不是很奇怪吗?
    • @BirgerSkogengPedersen 当您使用完全以 Angular 样式编写的代码时,Angular 可以非常简洁明了(在这种情况下,这意味着使用 ng-click 和在您的范围内定义的方法),但你是对的:当你需要在其他 JavaScript 和 Angular 代码之间进行通信时,它可能会非常冗长。恐怕我没有足够的 Angular 经验来真正评论如何处理这个问题。
    • 啊,击败我到 .scope() Jeremy!至于您的问题,@BirgerSkogengPedersen,是的,这是对 Angular 的主要抱怨之一 - 一般的 Angular 响应是,如果您使用外部代码修改范围,那么您就没有遵守 MVC,并且使您的代码更难维护。我发现这在处理项目要求的其他 3rd 方库时最常出现,并且通常处理它们的最佳方法是将 3rd 方功能包含在全局范围内,或者包含在自定义指令的编译和链接函数中为它。
    • @MaxPRafferty 感谢您提供的知识。以后我会尽量避免这样的解决方案
    • 对我不起作用。我的 ng-controller 位于具有 ng-app 的元素的子元素中。这是展示我在做什么的小提琴:jsfiddle.net/jjr5v9Ld/1
    【解决方案2】:

    Jeremy's answer 确实不错,虽然现在 Angular 变了,不能再工作了,除非你加上这行代码:

    $scope = $scope.$$childHead;
    

    所以,修改后的函数应该是这样的

    function change() {
        var appElement = document.querySelector('[ng-app=myApp]');
        var $scope = angular.element(appElement).scope();
        $scope = $scope.$$childHead; // add this and it will work
        $scope.$apply(function() {
            $scope.data.age = 20;
        });
    }
    

    【讨论】:

    • 我试过了,但我的编辑被拒绝了。检查这个:meta.stackoverflow.com/questions/306785/…
    • 为什么在 1.1 和 1.6 版本之间会有重大变化?在使用前 30 分钟后已经讨厌 AngularJS。
    • 奇怪,这里 Jeremy 的回答在 1.6.4 jsfiddle.net/kj8Rc/319 中不起作用。好的,我发现了,这是因为ng-appng-controller在不同的div中。
    • 无法在 1.7 上运行...即使 ng-app 和 ng-controller 在同一个 div 中
    • 我也省略了 .data。即 $scope.$$childHead.age = 20;
    【解决方案3】:

    http://jsfiddle.net/MaxPRafferty/GS6Qk/

    您希望将 ng-click 属性设置为您范围内的函数,如下所示:

    var person = {
        age: 16
    };
    
    // Create module
    var myApp = angular.module('myApp', []);
    myApp.factory('Data', function() {
        return person;
    });
    
    function FirstCtrl($scope, Data) {
        $scope.data = Data;
        $scope.update = function(){
            $scope.data.age = 20;
        }
    }
    

    【讨论】:

    • 感谢您的回复,但我仍然不明白按钮如何改变人的年龄。即使是这样,我怎么能改变控制者之外的人的年龄?对不起,如果我原来的问题有点不清楚
    • 如果可以直接赋值,为什么还需要工厂?
    【解决方案4】:

    使用 Jeremy Banks 的完美答案,在一行中完成,尽管我引用的是控制器与应用程序:

    angular.element('[ng-controller=myController]').scope().$apply(function(x){ x.foo = "bar"; });
    

    【讨论】:

      【解决方案5】:

      只需使用较短的 $timeout

      var whatever = 'xyz';
      $timeout(function(){
          $scope.yourModel.yourValue = whatever;
      }, 0);
      

      你就完成了。

      我之前尝试过来自 www 的所有 $apply hack,但它们都不起作用。但是这个 $timeout 在任何情况下总是像魅力一样工作。 您所需要的只是 $scope 和 $timeout 的引用。

      Wy 及其工作原理:

      // Imagine an angular buildin-function
      angular.$queue = function(fn){
          $timeout(fn, 0);
      }
      

      它的工作原理基本上就像一个队列。但请注意,它是异步的。

      【讨论】:

      • 因为 $timeout 是在 angulars 摘要例程中处理的。零 (0) 时间的 $timeout 与队列完全一样。或者换句话说:使用 $timeout(fn, 0) 你说“嘿,角,请在完成当前工作后立即执行。”
      【解决方案6】:

      当值在指令之外被修改时,ng-model 指令调用 $render 方法。通过读取 $viewValue 属性获取新值。看:https://jsfiddle.net/cesar_ade/g5ybs6ne/

      ctrl.$render=function(){
          setSelected(ctrl.$viewValue || 'Not Sure');
      }
      

      【讨论】:

        猜你喜欢
        • 2019-12-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多