Как изменить данные AngularJS вне рамок?
После нескольких часов разочаровывающих поисков я чувствую, что мне нужно представить свой вопрос здесь. Я заранее извиняюсь, если этот вопрос каким-то образом до ответа, но ни один из моих поисков не помог до сих пор. Итак, вот мой вопрос:
Мой код 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
?
Ответы
Ответ 1
⚠️ Предупреждение: Этот ответ старый, не отражает лучших практик и может быть несовместим с более новыми версиями Angular.
Ответ MaxPRafferty верный - использование функции в области часто является лучшим способом сделать это, но есть и другой вариант. Вы можете использовать метод angular.element(...).scope()
для доступа к области Angular из несвязанного JavaScript. Выберите область верхнего уровня для приложения, настроив на него элемент с указанным атрибутом ng-app
, с чем-то вроде обработчика кликов:
function change() {
var appElement = document.querySelector('[ng-app=myApp]');
var $scope = angular.element(appElement).scope();
$scope.$apply(function() {
$scope.data.age = 20;
});
}
Попробуйте в этой скрипте.
Shaun только что указал, что Angular обрабатывает только "часы" или "часы", привязки "во время вызова $digest()
. Если вы просто изменяете свойства $scope
напрямую, изменения могут не отображаться немедленно, и вы можете получить ошибки.
Чтобы вызвать это, вы можете вызвать $scope.$apply()
, который будет проверять наличие грязных областей и правильно обновлять что-либо связанное. Передача функции, которая выполняет работу внутри $scope.$apply
, позволит Angular также поймать любые исключения. Это поведение объясняется в документации для области.
Ответ 2
Ответ Джереми действительно хорош, хотя теперь 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;
});
}
Ответ 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
Используя отличный ответ Джереми Бэнкса, сделанный в одной строке, хотя я ссылаюсь на контроллер и приложение:
angular.element('[ng-controller=myController]').scope().$apply(function(x){ x.foo = "bar"; });
Ответ 5
Просто используйте короткий $timeout
var whatever = 'xyz';
$timeout(function(){
$scope.yourModel.yourValue = whatever;
}, 0);
и все готово.
Я пробовал все эти $apply hacks со всего www раньше, и все они не работали. Но этот $timeout работает всегда как charme и в каждом случае.
Все, что вам нужно, это ссылка на ваш $scope и $timeout.
Wy и как это работает:
// Imagine an angular buildin-function
angular.$queue = function(fn){
$timeout(fn, 0);
}
Он работает в основном как очередь. Но имейте в виду, что это асинхронно.
Ответ 6
С методом $render метод вызывается директивой ng-model, когда значение было изменено вне директивы. Получите новое значение, прочитав свойство $viewValue. Посмотрите: https://jsfiddle.net/cesar_ade/g5ybs6ne/
ctrl.$render=function(){
setSelected(ctrl.$viewValue || 'Not Sure');
}