Por que formar indefinido dentro do ng-include ao marcar $ pristine ou $ setDirty ()?
O código a seguir gera o erro "TypeError: Não é possível ler a propriedade '$ pristine' de indefinido" quando clico no botão "verificar".
app.controller('MainCtrl', function($scope) {
// other stuff
})
.controller('Ctrl2', function($scope) {
$scope.product = {description:'pump'};
$scope.output = 'unknown';
// uncomment to avoid undefined error, still can't see $pristine
// $scope.formHolder = {};
$scope.checkForm = function() {
$scope.descriptionTest = $scope.product.description;
if ($scope.formHolder.productForm.$pristine) {
$scope.output = 'yes';
}
if ($scope.formHolder.productForm.$dirty) {
$scope.output = 'no'
}
}
});
html
<body ng-controller="MainCtrl">
<div >
<ng-include ng-controller="Ctrl2" src="'myForm.html'"></ng-include>
</div>
</body>
myForm.html
<form name="productForm" novalidate>
<h2>myForm</h2>
description: <input type="text" name="description" ng-model="product.description"/>
<br>
<button ng-click="checkForm()">Check Form</button>
<br>
Form Pristine: {{output}}
<br><br>
I can see the description: {{descriptionTest}}
</form>
O problema é que meu Ctrl2 não pode ver o productForm. No começo, pensei que isso tivesse a ver com a herança prototípica que o ng-include faz quando cria um escopo filho, então tentei adicionar uma variável no Ctrl2:
$scope.productForm = {};
Isso eliminou o erro, mas meu controlador ainda não estava vendo corretamente $ imaculado ou $ sujo.
Finalmente consegui fazê-lo adicionando um objeto $ scope.formHolder acima do productForm:
.controller('Ctrl2', function($scope) {
$scope.product = {description:'pump'};
$scope.output = 'unknown';
// uncomment to avoid undefined error, still can't see $pristine
$scope.formHolder = {};
$scope.checkForm = function() {
$scope.descriptionTest = $scope.product.description;
if ($scope.formHolder.productForm.$pristine) {
$scope.output = 'yes';
}
if ($scope.formHolder.productForm.$dirty) {
$scope.output = 'no'
}
}
});
html
<form name="formHolder.productForm" novalidate>
Por que isso funciona? E existe uma maneira melhor de fazer isso?
Acabei assim porque tinha um formulário de trabalho e um controlador / modelo que queria reutilizar em outro lugar. Provavelmente eu deveria fazer uma diretiva, mas tudo funcionou bem, exceto os recursos $ pristine e $ dirty do formulário - todos os vars do modelo ng foram aprovados corretamente.
Como posso definir um formulário contido em um ng-include para ser prestine? tem uma resposta que "quebra todas as regras", mas parecia mais complicada.
Quando escrevo, quando o formulário Controller adiciona $ pristine ao escopo e a qual escopo?
Editar / Responder:
Minha pergunta original pode ser resumida em confusão sobre como a diretiva de formulário grava no escopo. Eu tive a impressão de que isso levaria a coisa
<form name="productForm">...
e adicionar propriedades a ele, como
$scope.productForm.$pristine = function() {...}
no entanto, ele grava diretamente em cima do productForm:
$scope.productForm = formObject;
Portanto, o objeto de formulário é armazenado no Filho e não no pai, conforme explicado na resposta selecionada.
A pepita chave na herança do escopo filho que me ajudou é que a cadeia é consultada na leitura, mas não na escrita. Portanto, se você definir algo como childScope.myThing.property = '123', embora pareça uma gravação, primeiro será necessário fazer uma leitura para descobrir o que é o myThing. Considerando que definir childScope.myThing = '567' é uma gravação direta e não envolve a análise da cadeia pai. Tudo isso é melhor explicado em:Quais são as nuances da herança prototípica / prototípica do escopo no AngularJS?