47

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

我的 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函数中修改人的年龄?

4

6 回答 6

73

⚠️警告:这个答案很旧,不反映最佳实践,并且可能与较新版本的 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;
    });
}

在这个 Fiddle 中尝试一下。

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

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

于 2013-07-15T14:26:14.850 回答
15

Jeremy 的回答真的很好,虽然现在 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;
    });
}
于 2015-09-24T22:19:02.250 回答
5

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;
    }
}
于 2013-07-15T14:14:46.933 回答
5

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

angular.element('[ng-controller=myController]').scope().$apply(function(x){ x.foo = "bar"; });
于 2016-03-23T20:31:44.263 回答
3

只需使用短暂的 $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);
}

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

于 2016-04-09T22:35:52.423 回答
0

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

ctrl.$render=function(){
    setSelected(ctrl.$viewValue || 'Not Sure');
}
于 2015-10-08T20:49:31.480 回答