可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
After hours of frustrating searches I feel I need to submit my question here. I apologize in advance if this question is somehow answered before but none of my searches has helped so far. So here's my question:
My JavaScript code is creating an object, which is modified and monitored by AngularJS. On some events (like loading a previous setting of the object), I wish to change the properties of this object from outside the scope. The problem is that the inputs does not change...
Here's an example of how I wish to perform these changes:
HTML code:
<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 Code:
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;
}
When I now press the "Change to 20" button, nothing happens. How can I modify the person's age from the change
function?
回答1:
⚠️ Warning: This answer is old, does not reflect best practices, and may not be compatible with newer versions of Angular.
MaxPRafferty's answer is correct - using a function in the scope is often the nicer way to do this - but there is another option. You can use the angular.element(...).scope()
method to access an Angular scope from unrelated JavaScript. Select the top-level scope for the app by targeting the element that has the ng-app
attribute specified, with something like in your click handler:
function change() {
var appElement = document.querySelector('[ng-app=myApp]');
var $scope = angular.element(appElement).scope();
$scope.$apply(function() {
$scope.data.age = 20;
});
}
Try it out in this Fiddle.
Shaun just pointed out that Angular will only process any "watches" or "bindings" during a $digest()
call. If you just modify the properties of the $scope
directly, the changes may not be reflected immediately and you may gets bugs.
To trigger this you can call $scope.$apply()
which will check for dirty scopes and update anything bound correctly. Passing a function that does the work inside $scope.$apply
will allow Angular to catch any exceptions as well. This behaviour is explained in the documentation for Scope.
回答2:
Jeremy's answer is really good, though now Angular has changed, and will no longer work, unless you add this line of code:
$scope = $scope.$$childHead;
So, the changed function should look like this
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;
});
}
回答3:
http://jsfiddle.net/MaxPRafferty/GS6Qk/
You want set your ng-click attribute to a function in your scope, as follows:
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:
Using Jeremy Banks' perfect answer, done in one line, though I'm referencing the controller vs the app:
angular.element('[ng-controller=myController]').scope().$apply(function(x){ x.foo = "bar"; });
回答5:
Simply use a short $timeout
var whatever = 'xyz';
$timeout(function(){
$scope.yourModel.yourValue = whatever;
}, 0);
and you are done.
I tried all those $apply hacks from around the www before and they all didn't work. But this $timeout works always like a charme and in every case.
All you need is a reference of your $scope and $timeout.
Wy and how it works:
// Imagine an angular buildin-function
angular.$queue = function(fn){
$timeout(fn, 0);
}
It works basically like a queue. But be aware that it is async.
回答6:
With $render method is called by the ng-model directive when the value has been modified outside the directive. Get new value by reading the $viewValue property. Look: https://jsfiddle.net/cesar_ade/g5ybs6ne/
ctrl.$render=function(){
setSelected(ctrl.$viewValue || 'Not Sure');
}