AngularJs не может получить доступ к объекту формы в контроллере ($ scope)

Я использую bootstrap-ui более конкретно модальные окна. И у меня есть форма в модальном режиме, я хочу создать экземпляр объекта проверки формы. Поэтому я в основном делаю это:

<form name="form">
    <div class="form-group">
        <label for="answer_rows">Answer rows:</label>
        <textarea name="answer_rows" ng-model="question.answer_rows"></textarea>
    </div>
</form>

<pre>
    {{form | json}}
</pre

Я вижу объект формы в html файле без проблем, однако, если я хочу получить доступ к объекту проверки формы от контроллера. Он просто выводит мне пустой объект. Вот пример контроллера:

.controller('EditQuestionCtrl', function ($scope, $modalInstance) {
    $scope.question = {};
    $scope.form = {};

    $scope.update = function () {
        console.log($scope.form); //empty object
        console.log($scope.question); // can see form input
    };
});

Каковы могут быть причины, по которым я не могу получить доступ к $scope.form от контроллера?

Ответ 1

Только для тех, кто не использует $scope, а скорее this, в своем контроллере вам придется добавить псевдоним контроллера, предшествующий имени формы. Например:

<div ng-controller="ClientsController as clients">
  <form name="clients.something">
  </form>
</div>

а затем на контроллере:

app.controller('ClientsController', function() {
  // setting $setPristine()
  this.something.$setPristine();
};

Надеюсь, что это также будет способствовать общему набору ответов.

Ответ 2

Обычный способ, если ng-controller является родителем элемента формы: удалите эту строку:

$scope.form = {};

Если angular устанавливает форму в ваши контроллеры $scope, вы перезаписываете ее пустым объектом.


Как заявлял ОП, это не так. Он использует $modal.open, поэтому контроллер не является родителем формы. Я не знаю хорошего решения. Но эту проблему можно взломать:

<form name="form" ng-init="setFormScope(this)">
...

и в вашем контроллере:

$scope.setFormScope= function(scope){
   this.formScope = scope;
}

а затем в вашей функции обновления:

$scope.update = function () {
    console.log(this.formScope.form); 

};

Ответ 3

Посмотрите на исходный код "модального" angular ui bootstrap, вы увидите, что директива имеет

transclude: true

Это означает, что модальное окно создаст новую дочернюю область, родительский элемент которой является областью контроллера $, как дочерний элемент области действия. Тогда "форма" может быть доступна только вновь созданной дочерней областью.

Одним из решений является определение var в области контроллера, например

$scope.forms = {};

Затем для имени формы мы используем что-то вроде forms.formName1. Таким образом, мы могли бы получить доступ к нему из нашего контроллера, просто позвонив $scope.forms.formName1.

Это работает, потому что механизм наследования в JS является прототипной цепочкой. Когда дочерний объект пытается создать forms.formName1, он сначала пытается найти объект forms в своей области, который определенно не имеет его, поскольку он создается "на лету". Затем он попытается найти его от родителя (вплоть до цепи прототипа), и здесь, поскольку мы определили его в области контроллера, он использует этот объект "forms", который мы создали, для определения переменной formName1. В результате мы все еще можем использовать его в нашем контроллере, чтобы делать такие вещи, как:

if($scope.forms.formName1.$valid){
      //if form is valid
}

Подробнее о трансклюзии, посмотрите на видео ниже Misco с 45 минут. (это, вероятно, самое точное объяснение того, что такое трансключенные области, которые я когда-либо обнаружил!!!)

www.youtube.com/watch?v=WqmeI5fZcho

Ответ 4

Нет необходимости в обмане ng-init, поскольку проблема заключается в том, что $scope.form не задается при запуске кода контроллера. Удалите инициализацию form = {} и получите доступ к форме, используя часы:

$scope.$watch('form', function(form) {
  ...
});

Ответ 5

Я использую документированный подход.

https://docs.angularjs.org/guide/forms

поэтому, пользователь имя формы, на "сохранить" клик, например, просто передайте formName в качестве параметра и hey presto form, доступный в методе save (где formScopeObject поддерживается на основе спецификаций ng-моделей, которые вы задали в своей форме ИЛИ если вы редактируете это будет объект хранения редактируемого элемента, то есть учетной записи пользователя)

<form name="formExample" novalidate>

<!-- some form stuff here -->
Name
<input type="text" name="aField" ng-model="aField" required="" />

<br /><br />

<input type="button" ng-click="Save(formExample,formScopeObject)" />

</form>

Ответ 6

Чтобы расширить ответ от пользователя1338062: решение, которое я использовал несколько раз, чтобы инициализировать что-то в моем контроллере, но должен был ждать, пока он действительно будет доступен для использования:

var myVarWatch = $scope.$watch("myVar", function(){
    if(myVar){
        //do whatever init you need to
        myVarWatch();    //make sure you call this to remove the watch
    }
});

Ответ 7

Для тех, кто использует Angular 1.5, мое решение было $смотреть форму на стадии postlink:

$postLink() {
      this.$scope.$watch(() => this.$scope.form.$valid, () => {
      });
    }