如何将ng-include中包含的表单设置为prestine?

时间:2022-08-25 23:58:15

I have the following code:

我有以下代码:

<div modal="modal.shouldBeOpen" close="close()" options="opts">
    <div class="modal-body">
        <form novalidate name="itemForm" style="margin-bottom: 0px;">

Which is contained inside the included file modal.html

哪个包含在包含的文件modal.html中

<div data-ng-controller="AdminController">
   <ng-include src="'/Content/app/admin/partials/grid-subject.html'"></ng-include >
   <ng-include src="'/Content/app/admin/partials/modal.html'"></ng-include>
</div>

In my AdminController controller I am trying to use the following code to reset the form to pristine:

在我的AdminController控制器中,我尝试使用以下代码将表单重置为pristine:

$scope.itemForm.$setPristine();

When I do this it tells me that "itemForm" is undefined.

当我这样做时,它告诉我“itemForm”是未定义的。

Is there a way I can set the contents of the form to pristine. I assume this is a scope problem but I am not sure how to fix it. I tried the one solution of removing the second include and pasting the code in directly. This solution works.

有没有办法可以将表单的内容设置为pristine。我认为这是一个范围问题,但我不知道如何解决它。我尝试了一个解决方案,删除第二个包含并直接粘贴代码。该解决方案有效。

However we want to be able to reuse code so I would like to be able to do this with an include for modal.html

但是我们希望能够重用代码,因此我希望能够使用include for modal.html来实现这一点

Note that the reason we would like to do this is because we have something like the following on our modal.html:

请注意,我们希望这样做的原因是因为我们的modal.html上有以下内容:

    <button
        class="btn float-right"
        data-ng-disabled="itemForm.$pristine"
        data-ng-click="modalReset()"
        data-ng-show="modal.resetButton">
        Reset</button>
</form>

So we are actually inside of the itemForm and would like to set it to $pristine from the button inside.

所以我们实际上是在itemForm里面,并希望从里面的按钮将它设置为$ pristine。

4 个解决方案

#1


8  

This answer will break all the rules (i.e., DOM traversal inside a controller), but here it is anyway...

这个答案将打破所有规则(即在控制器内部进行DOM遍历),但无论如何......

.controller('AdminController', ['$scope','$element',
function($scope, $element) {
  $scope.$on('$includeContentLoaded', function() {
    var childFormController = $element.find('form').eq(0).controller('form');
    console.log(childFormController);
    childFormController.$setPristine();
  });
}]);

We wait for the ng-included content to load, then from the $element where AdminController is defined, we look for form elements, pick the first one, then get its FormController.

我们等待加载ng包含的内容,然后从定义了AdminController的$元素中,我们查找表单元素,选择第一个,然后获取其FormController。

Plunker

Plunker

If you are only calling $setPristine() as a result of some user interaction, you won't need to look for the $includedContentLoaded event – I only had to do that because I didn't want to create any UI component to trigger the operation, and when the controller first runs, the form doesn't exist yet.

如果你只是通过一些用户交互调用$ setPristine(),你将不需要查找$ includedContentLoaded事件 - 我只需要这样做,因为我不想创建任何UI组件来触发操作,当控制器第一次运行时,表单尚不存在。

See also AngularJS: Access formController of a form placed inside transcluded directive from parent controller which deals with the similar problem of trying to access a child from a parent.

另请参阅AngularJS:访问来自父控制器的transcluded指令内的表单的formController,它处理尝试从父级访问子级的类似问题。

A cleaner solution: define a directive (use it on the ng-include element) and pass it an AdminController function as an attribute. In the directive's link function, call that method and pass the FormController as a parameter. Then the AdminController will have a reference to the desired FormController. (I did not bother coding this up, as I'm not sure you want a solution where you have to use a directive along with ng-include.)

更清晰的解决方案:定义指令(在ng-include元素上使用它)并将AdminController函数作为属性传递给它。在指令的link函数中,调用该方法并将FormController作为参数传递。然后AdminController将引用所需的FormController。 (我没有打扰这个编码,因为我不确定你需要一个解决方案,你必须使用指令和ng-include。)

#2


5  

Well, one way to do it is to broadcast an event, like so:

好吧,一种方法是广播一个事件,如下:

angular.module('myApp',[])
    .controller('AdminCtrl',function($scope){
        $scope.modalReset = function(){
            $scope.$broadcast('modal-reset');
        };
    })
    .controller('ModalCtrl', function($scope){
        $scope.$on('modal-reset', function(){
            $scope.itemForm.$setPristine();
        });
    });

This way you don't have to traverse the dom.

这样你就不必遍历dom了。

#3


1  

Do not break the rules :) Just define the variable (empty object) in the controller and use it while defining your form. Since angular JS uses scope prototypes under the hood, when form will try to access the inner scope (to bootstrap the variable), it will first go via scope chain and try to find the same variable in the parent's scope.

不要违反规则:)只需在控制器中定义变量(空对象)并在定义表单时使用它。由于角度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>

Link for reference http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

链接参考http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

#4


0  

If you want to achieve this as the result of some user interaction, in my opinion a much more cleaner and 'angular' way of doing it would be to use a custom directive which will set the form to pristine (i.e. when the user wants to clear the form by pressing esc or clicking a button or whatever).

如果你想通过一些用户交互来实现这一点,我认为更简洁,更有棱角的做法是使用自定义指令将表单设置为原始(即当用户想要按esc或单击按钮或其他任何内容清除表单。

app.directive("formCleaner",
  function () {
        return {
            restrict: 'E',
            require: '^form',
            scope: {
                callback: '&',
                defaultText:'@'
            },
            template: '<button type="button" ng-click="setFormToPristine()" class="btn btn-warning"  >{{defaultText}}</button>',
            link: function (scope, element, attrs, formCtrl) {
                scope.setFormToPristine = function () {
                    formCtrl.$setPristine();
                    scope.callback();
              };
            }
  };
});

and simply hook it up to some button in your form:

并简单地将其连接到表单中的某个按钮:

<form name="testForm">
      <input type="text" ng-model="someModel" />
      <hr/>
      <input type="button" value="submit form" class="btn btn-primary" ng-disabled="testForm.$pristine" 
        ng-click=submitForm(testForm) />
      <form-cleaner callback="resetFormCallback(testForm)" default-text="Clear Form"></form-cleaner>
</form>

And if you're looking to set the form to pristine directly from the controller, (not as a result of some user interaction) such as success response from a POST, then one way would be to assign a callback to the directive which will be responsible for clearing the form and then invoking that callback from the controller. In your view:

如果您希望直接从控制器将表单设置为pristine(不是由于某些用户交互),例如来自POST的成功响应,那么一种方法是为指令分配回调,这将是负责清除表单,然后从控制器调用该回调。在你看来:

<form-cleaner callback="resetFormCallback(testForm)" default-text="Clear Form"></form-cleaner>

and the controller:

和控制器:

 $scope.resetFormOnSubmitCallback=function(cb){
    $log.warn("simulating $http POST call.....");
      $timeout(function() {
            cb();
            $scope.someModel=null;
        }, 3000)
  }

and the directive:

和指令:

return {
            restrict: 'E',
            require: '^form',
            scope: {
                callback: '&',
                defaultText:'@',
                ngDisabled:'='
            },
            template: '<button type="button" ng-disabled="ngDisabled" ng-click="submitForm()" class="btn btn-primary"  >{{defaultText}}</button>',

            link: function (scope, element, attrs, formCtrl) {
            var setFormToPristine=function(){
              $log.log("setting form to prsitine....");
              formCtrl.$setPristine();
            };  

                scope.submitForm = function () {
                scope.callback({
                    onFormSubmittedCallback:setFormToPristine
                });
              };
            }
  };

See plunk

见插件

#1


8  

This answer will break all the rules (i.e., DOM traversal inside a controller), but here it is anyway...

这个答案将打破所有规则(即在控制器内部进行DOM遍历),但无论如何......

.controller('AdminController', ['$scope','$element',
function($scope, $element) {
  $scope.$on('$includeContentLoaded', function() {
    var childFormController = $element.find('form').eq(0).controller('form');
    console.log(childFormController);
    childFormController.$setPristine();
  });
}]);

We wait for the ng-included content to load, then from the $element where AdminController is defined, we look for form elements, pick the first one, then get its FormController.

我们等待加载ng包含的内容,然后从定义了AdminController的$元素中,我们查找表单元素,选择第一个,然后获取其FormController。

Plunker

Plunker

If you are only calling $setPristine() as a result of some user interaction, you won't need to look for the $includedContentLoaded event – I only had to do that because I didn't want to create any UI component to trigger the operation, and when the controller first runs, the form doesn't exist yet.

如果你只是通过一些用户交互调用$ setPristine(),你将不需要查找$ includedContentLoaded事件 - 我只需要这样做,因为我不想创建任何UI组件来触发操作,当控制器第一次运行时,表单尚不存在。

See also AngularJS: Access formController of a form placed inside transcluded directive from parent controller which deals with the similar problem of trying to access a child from a parent.

另请参阅AngularJS:访问来自父控制器的transcluded指令内的表单的formController,它处理尝试从父级访问子级的类似问题。

A cleaner solution: define a directive (use it on the ng-include element) and pass it an AdminController function as an attribute. In the directive's link function, call that method and pass the FormController as a parameter. Then the AdminController will have a reference to the desired FormController. (I did not bother coding this up, as I'm not sure you want a solution where you have to use a directive along with ng-include.)

更清晰的解决方案:定义指令(在ng-include元素上使用它)并将AdminController函数作为属性传递给它。在指令的link函数中,调用该方法并将FormController作为参数传递。然后AdminController将引用所需的FormController。 (我没有打扰这个编码,因为我不确定你需要一个解决方案,你必须使用指令和ng-include。)

#2


5  

Well, one way to do it is to broadcast an event, like so:

好吧,一种方法是广播一个事件,如下:

angular.module('myApp',[])
    .controller('AdminCtrl',function($scope){
        $scope.modalReset = function(){
            $scope.$broadcast('modal-reset');
        };
    })
    .controller('ModalCtrl', function($scope){
        $scope.$on('modal-reset', function(){
            $scope.itemForm.$setPristine();
        });
    });

This way you don't have to traverse the dom.

这样你就不必遍历dom了。

#3


1  

Do not break the rules :) Just define the variable (empty object) in the controller and use it while defining your form. Since angular JS uses scope prototypes under the hood, when form will try to access the inner scope (to bootstrap the variable), it will first go via scope chain and try to find the same variable in the parent's scope.

不要违反规则:)只需在控制器中定义变量(空对象)并在定义表单时使用它。由于角度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>

Link for reference http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

链接参考http://blog.152.org/2014/07/angular-form-element-not-attaching-to.html

#4


0  

If you want to achieve this as the result of some user interaction, in my opinion a much more cleaner and 'angular' way of doing it would be to use a custom directive which will set the form to pristine (i.e. when the user wants to clear the form by pressing esc or clicking a button or whatever).

如果你想通过一些用户交互来实现这一点,我认为更简洁,更有棱角的做法是使用自定义指令将表单设置为原始(即当用户想要按esc或单击按钮或其他任何内容清除表单。

app.directive("formCleaner",
  function () {
        return {
            restrict: 'E',
            require: '^form',
            scope: {
                callback: '&',
                defaultText:'@'
            },
            template: '<button type="button" ng-click="setFormToPristine()" class="btn btn-warning"  >{{defaultText}}</button>',
            link: function (scope, element, attrs, formCtrl) {
                scope.setFormToPristine = function () {
                    formCtrl.$setPristine();
                    scope.callback();
              };
            }
  };
});

and simply hook it up to some button in your form:

并简单地将其连接到表单中的某个按钮:

<form name="testForm">
      <input type="text" ng-model="someModel" />
      <hr/>
      <input type="button" value="submit form" class="btn btn-primary" ng-disabled="testForm.$pristine" 
        ng-click=submitForm(testForm) />
      <form-cleaner callback="resetFormCallback(testForm)" default-text="Clear Form"></form-cleaner>
</form>

And if you're looking to set the form to pristine directly from the controller, (not as a result of some user interaction) such as success response from a POST, then one way would be to assign a callback to the directive which will be responsible for clearing the form and then invoking that callback from the controller. In your view:

如果您希望直接从控制器将表单设置为pristine(不是由于某些用户交互),例如来自POST的成功响应,那么一种方法是为指令分配回调,这将是负责清除表单,然后从控制器调用该回调。在你看来:

<form-cleaner callback="resetFormCallback(testForm)" default-text="Clear Form"></form-cleaner>

and the controller:

和控制器:

 $scope.resetFormOnSubmitCallback=function(cb){
    $log.warn("simulating $http POST call.....");
      $timeout(function() {
            cb();
            $scope.someModel=null;
        }, 3000)
  }

and the directive:

和指令:

return {
            restrict: 'E',
            require: '^form',
            scope: {
                callback: '&',
                defaultText:'@',
                ngDisabled:'='
            },
            template: '<button type="button" ng-disabled="ngDisabled" ng-click="submitForm()" class="btn btn-primary"  >{{defaultText}}</button>',

            link: function (scope, element, attrs, formCtrl) {
            var setFormToPristine=function(){
              $log.log("setting form to prsitine....");
              formCtrl.$setPristine();
            };  

                scope.submitForm = function () {
                scope.callback({
                    onFormSubmittedCallback:setFormToPristine
                });
              };
            }
  };

See plunk

见插件