Why form undefined inside ng-include when checking $pristine or $setDirty()?

前端 未结 3 449
鱼传尺愫
鱼传尺愫 2020-12-01 14:06

The following code throws the error \"TypeError: Cannot read property \'$pristine\' of undefined\" when I click the \"check\" button.

app.controller(\'MainCt         


        
3条回答
  •  我在风中等你
    2020-12-01 14:30

    To understand why the solution with formHolder work you have to understand JavaScript prototypes chain first. Let's illustrate the first case without formHolder in the following pseudo code:

    $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 
    }
    

    When the form directive is parsed it creates FormController which is set on the $scope property under key indicated in name attribute value. This is pretty much equivalent to:

    $childScope.productForm = $formCtrl;
    

    After which the 2 scopes look like this:

    $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 
    }
    

    So you actually ended up with 2 properties on different scopes holding different objects. Now in the second case you have the following situation:

    $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 
    }
    

    When the form directive is setting FormController instance on the $scope this time it uses different property chain:

    $childScope.formHolder.productForm = $formCtrl;
    

    Which is equivalent to writing:

    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 it helps to understand why the second option works. As for the second part of you question - your solution is simple and perfectly viable - but there are couple of other ways to handle it which is best depends on the actual usage context:

    • using directive without child scope to extract common markup and parts of functionality
    • using directive with child scope that would communicate state changes either via direct parent scope property access or via emitted events
    • using a custom include directive that would not create child scope

提交回复
热议问题