2014-05-15 17 views
25

當我單擊「檢查」按鈕時,以下代碼將引發錯誤「TypeError:Can not read property'$ pristine'of undefined」。

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> 

plunkr

的問題是,我CTRL 2不能看到productForm。起初我以爲這曾與原型繼承做NG-包括做時,它能使孩子的範圍,所以我想在CTRL 2加入一個變量:

$scope.productForm = {}; 

這擺脫了錯誤的,但我的控制器仍然沒有正確地看到$ pristine或$ dirty。

我終於得到它的工作通過增加productForm高於$ scope.formHolder對象:

plunkr

.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> 

爲什麼這項工作?有沒有更好的方法來做到這一點?

我結束了這種方式,因爲我有一個工作表&控制器/模板,我想在其他地方重用。我應該做一個指令,但除了表單的$ pristine和$ dirty特徵之外,一切都正常工作 - 所有的ng-model vars都正確傳遞。

How can I set a form contained inside a ng-include to be prestine?有一個答案,「打破所有規則」,但似乎更復雜。

當我寫的時候,表單控制器添加$ pristine到範圍,以及什麼範圍?

編輯/答:

我原來的問題都可以歸結爲混淆形式指令如何寫入範圍。我的印象是,它將採取的東西

<form name="productForm">... 

和屬性添加到它,就像

$scope.productForm.$pristine = function() {...} 
但是

,它直接寫在productForm的頂部:

$scope.productForm = formObject; 

所以,表單對象存儲在Child中,而不是按照所選答案中的說明存儲在父項中。

幫助我的子範圍繼承關鍵塊是鏈閱讀而不是書寫。所以如果你設置了類似childScope.myThing的東西。property ='123',雖然它看起來像寫,但它首先必須做一個閱讀,以找出myThing是什麼。而設置childScope.myThing ='567'是一個直接寫入,並且不涉及根本看父鏈。這一切更好地解釋在:What are the nuances of scope prototypal/prototypical inheritance in AngularJS?

回答

14

要理解爲什麼解決方案與formHolder工作,你必須首先了解JavaScript prototypes chain。讓我們來舉例說明而formHolder在下面的僞代碼第一種情況:

$parentScope = { 
    //I'm a parent scope inside Ctrl2 
    productForm:{} //to avoid undefined reference error 
} 

$childScope = { 
    //I'm a child scope created by by ng-include 
    __protototype__: $parentScope 
} 

form指令解析它創建FormController這是對下name屬性值指示鍵$scope屬性設置。這是非常等價於:

$childScope.productForm = $formCtrl; 

之後,2個示波器是這樣的:

$parentScope = { 
    //I'm a parent scope inside Ctrl2 
    productForm:{} //to avoid undefined reference error 
} 

$childScope = { 
    //I'm a child scope created by by ng-include 
    productForm: $formCtrl 

    __protototype__: $parentScope 
} 

所以你實際上結束了2性質上不同範圍持有不同的對象。 現在在第二種情況下,你有以下情況:

$parentScope = { 
    //I'm a parent scope inside Ctrl2 
    formHolder:{} //to avoid undefined reference error 
} 

$childScope = { 
    //I'm a child scope created by by ng-include 
    __protototype__: $parentScope 
} 

form指令設置在$scope它使用不同的產業鏈這個時候FormController實例:

$childScope.formHolder.productForm = $formCtrl; 

即相當於寫作:

var formHolder = $childScope.formHolder; //since formHolder isn't defined on $childScope 
//the JS runtime will look for it in the prototypes chain and find it inside $parentScope 
//so here formHolder is the very same object you created and set on $parentScope 
formHolder.productForm = $formCtrl; 

Hope它有助於理解第二個選項爲什麼起作用。至於你的第二部分的問題 - 你的解決方案很簡單,完全可行的 - 但也有一些其他的方法來處理它,這是最好取決於實際使用環境:使用指令無子範圍提取

  • 常見的標記和使用指導與溝通會無論是通過直接父作用域屬性訪問或通過使用custom include directive發出的事件
  • ,不會創建子範圍狀態變化小孩範圍功能
  • 零件
+0

在angularJS它是順路點符號。 – Walfrat

0

我知道這是一個老問題,但我有一個類似的問題,我改變了HTML,並將我的ng-controller包含在html文件中。

所以不是

<ng-include ng-controller="Ctrl2" src="'myForm.html'"></ng-include> 

變化太

<ng-include="'myForm.html'"></ng-include> 

然後在myForm.html文件,包裹在一個div的代碼,並添加NG控制器屬性,讓你的myForm的。HTML將成爲

<div ng-controller="Ctrl2"> 
    <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> 
</div> 

現在你的孩子控制器是NG-包括範圍

1

只要定義在控制器中的變量(空對象),並在定義表單使用中。由於角JS使用範圍原型,當表單嘗試訪問內部範圍(引導變量)時,它將首先通過範圍鏈去嘗試在父範圍內找到相同的變量。

<!—- The vars should live in the controller. I placed them here for the example. -—> 
<div ng-controller=「controllerName」 ng-init="form={}; model={}" > 
    <div ng-include=「 ‘path-to-the-template’ 」></div> 
</div> 

<!—- Inside path-to-the-template -—> 
<form name="form.createUser"> 
    <input name="name" ng-model="model.name" /> 
    <input name="email" ng-model="model.email" /> 
</form> 

鏈接以供參考http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

相關問題