How to properly control the $ dirty and $ pristine state of the Angular directive

I am trying to create an angular directive that will compose a KendoUI TreeView control and text input so that it searches for the entered text and selects the element. I have this functionality, but I would like the directive to behave well in the form, so that when the value of the flag is changed, the dirty property is set.

Unfortunately, now it is only observed that when someone enters text into the input file, it becomes dirty (undesirable behavior) and checking the checkbox has no effect.

I was hoping to call $ setDirty () on the form, but it is not visible for the functions that I have, and I was hoping there was a clean way to make this visible, and not add it to $ scope, t solve the $ dirty problem set to true, but also by entering search text.

I created Plunk to demonstrate the problem.

Here is the code for the directive:

var serviceRoot = "http://demos.telerik.com/kendo-ui/service";
 angular.module("KendoDemos", ["kendo.directives"])
   .controller("MyCtrl", function($scope, $http) {
     $scope.treeData = new kendo.data.HierarchicalDataSource({
       data: [{
         text: "Cat"
       }, {
         text: "Dog",
         items: [{
           text: "Fido"
         }, {
           text: "Rover"
         }]
       }, {
         text: "Rabbit",
         checked: true
       }]
     });
   });

 (function() {
   'use strict';


   var app = angular.module('KendoDemos');

   var template = '<div>	<div class="input-group">		<input type="text" ng-click="textNotFound=false"			   class="form-control" placeholder="Find node"			   ng-model="searchText" ng-enter="search()" ng-esc="searchText=\'\';textNotFound = false;">		<div class="input-group-btn">			<span class="btn btn-default" ng-click="search()"><span class="fa fa-search clickable"				style="font-size: 14px; height: 18px"></span></span>		</div>	</div>	<div id="treeview" kendo-tree-view="searchTree" k-data-source="dataSource" k-load-on-demand="false" k-on-check="onCheck(kendoEvent)"	      k-options="{checkboxes:true }">		<span k-template>{{dataItem.text}}</span>	</div></div>'

   app.directive('searchableTree', function() {
     //Usage:
     //<div data-searchable-tree ng-model="vm.treeData"></div>
     var directive = {
       template: template,
       require: '?^form',
       replace: true,
       transclude: true,
       scope: {
         'dataSource': '=ngModel',
         'controlId': '@id'
       },
       restrict: 'AE',
       link: function($scope, element, attrs, formCtrl) {
         $scope.search = function(id) {
           var tree = $scope.searchTree;
           var node = tree.findByText($scope.searchText);
           tree.expandTo($scope.searchTree.dataItem(node));
           tree.select(node);
           tree.dataItem(node).set("checked", true);
           //var checkbox = $(node).find(":checkbox");
           //checkbox.prop("checked", true);
         }
         $scope.setSelected = function(id) {
           alert(id);
         }
         $scope.onSelect = function(id) {
           alert(id);
         }
         $scope.onCheck = function(e) {
           var checkbox = $(e.node).find(":checkbox");
           var checked = checkbox.prop("checked");
           //updateValidity(e.node, checked);
         }
       }
     };
     return directive;
   });

   app.directive('ngEnter', function() {
     return function(scope, element, attrs) {
       element.bind("keydown keypress", function(event) {
         if (event.which === 13) {
           scope.$apply(function() {
             scope.$eval(attrs.ngEnter);
           });

           event.preventDefault();
         }
       });
     };
   });

   app.directive('ngEsc', function() {
     return function(scope, element, attrs) {
       element.bind("keydown keypress", function(event) {
         if (event.which === 27) {
           scope.$apply(function() {
             scope.$eval(attrs.ngEsc);
           });

           event.preventDefault();
         }
       });
     };
   });

 })();
/* Styles go here */

html {
  font-size: 12px;
  font-family: Arial, Helvetica, sans-serif;
}
#example {
  text-align: center;
}
.demo-section {
  display: inline-block;
  vertical-align: top;
  width: 320px;
  height: 300px;
  text-align: left;
  margin: 0 2em;
}
.clickable {
  cursor: pointer;
}
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1411/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1411/styles/kendo.default.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1411/styles/kendo.dataviz.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1411/styles/kendo.dataviz.default.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1411/styles/kendo.default.mobile.min.css" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

<script src="http://cdn.kendostatic.com/2014.3.1411/js/jquery.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.3.1411/js/angular.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.3.1411/js/kendo.all.min.js"></script>

<body>
  <div id="example" ng-app="KendoDemos" ng-controller="MyCtrl">
    <form name='myForm'>
      <div name='myTree' data-searchable-tree ng-model="treeData"></div>
    </form>
    <hr/>

    <div>Directive is {{myForm.myTree.$dirty ? 'dirty' : 'pristine'}}</div>
    <hr/>
    <div>Form is {{myForm.$dirty ? 'dirty' : 'pristine'}}</div>
  </div>


</body>
Run codeHide result
+4
source share
2 answers

08/28/2016 addendum: since writing this, I realized that the scope method is only available in debug mode. I do not recommend this for production code.

. , scope(), , . , :

  function dirtyParent(uid)
    {
      var formEl = angular.element(angular.element('#' + uid).closest('form'));

      var formScope = formEl.scope();

      var formName = formEl.attr('name');

      formScope[formName].$setDirty();
    }

DOM, , , , ( name ) $setDirty(). , $dirty.

, DOM $formController New Dev, , .

+2

, , , :

-:

require: "ngModel" . ng-model - , . ng-model DOM .

, require: "form".

:

, . , UI .

Angular docs .

ng- :

$dirty, , , ng-model (ng-model="searchText") , , .

ngModel (. src) DOM , .

- ng-model element.on('input') ( -), , "required" ngModel.

"" ngModel, , NULL, .

, , . pre-link :

link: {
  pre: function(scope, element){
     // this will trip the search, and apply a `nullFormCtrl` internally, 
     // which doesn't do anything.
     element.data("$formController", null); 
  }
}
+1

All Articles