From 5766a6a173dc1d65b9293fd5bd0bcbc21b0791ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matias=20Niemela=CC=88?= <matias@yearofmoo.com>
Date: Wed, 19 Feb 2014 14:08:25 -0500
Subject: [PATCH] fix(ngModel): ensure checkboxes and radio buttons are flagged
 as dirty when changed

Closes #569
Closes #585
---
 lib/directive/ng_model.dart       |  2 ++
 test/directive/ng_model_spec.dart | 52 +++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart
index 1ac6f9dce..7621a0c2e 100644
--- a/lib/directive/ng_model.dart
+++ b/lib/directive/ng_model.dart
@@ -141,6 +141,7 @@ class InputCheckboxDirective {
     };
     inputElement.onChange.listen((value) {
       scope.$apply(() {
+        ngModel.dirty = true;
         ngModel.viewValue = inputElement.checked
             ? ngTrueValue.readValue(inputElement)
             : ngFalseValue.readValue(inputElement);
@@ -389,6 +390,7 @@ class InputRadioDirective {
     };
     radioButtonElement.onClick.listen((_) {
       if (radioButtonElement.checked) {
+        ngModel.dirty = true;
         scope.$apply(() => ngModel.viewValue = ngValue.readValue(radioButtonElement));
       }
     });
diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart
index ce1ea6106..25180c097 100644
--- a/test/directive/ng_model_spec.dart
+++ b/test/directive/ng_model_spec.dart
@@ -458,6 +458,20 @@ describe('ng-model', () {
       expect(element.checked).toBe(false);
     }));
 
+    it('should render as dirty when checked', inject((Scope scope) {
+      var element = _.compile('<input type="text" ng-model="my_model" probe="i" />');
+      Probe probe = _.rootScope.i;
+      var model = probe.directive(NgModel);
+
+      expect(model.pristine).toEqual(true);
+      expect(model.dirty).toEqual(false);
+
+      _.triggerEvent(element, 'change');
+
+      expect(model.pristine).toEqual(false);
+      expect(model.dirty).toEqual(true);
+    }));
+
 
     it('should update input value from model using ng-true-value/false', inject((Scope scope) {
       var element = _.compile('<input type="checkbox" ng-model="model" ng-true-value="1" ng-false-value="0">');
@@ -679,6 +693,44 @@ describe('ng-model', () {
       expect(greenBtn.checked).toBe(true);
       expect(blueBtn.checked).toBe(false);
     });
+
+    it('should render as dirty when checked', inject((Scope scope) {
+      var element = _.compile(
+        '<div>' + 
+        '  <input type="radio" id="on" ng-model="my_model" probe="i" value="on" />' +
+        '  <input type="radio" id="off" ng-model="my_model" probe="j" value="off" />' +
+        '</div>'
+      );
+      Probe probe = _.rootScope.i;
+
+      var model = probe.directive(NgModel);
+
+      var input1 = element.query("#on");
+      var input2 = element.query("#off");
+
+      expect(model.pristine).toEqual(true);
+      expect(model.dirty).toEqual(false);
+
+      expect(input1.classes.contains("ng-dirty")).toBe(false);
+      expect(input2.classes.contains("ng-dirty")).toBe(false);
+      expect(input1.classes.contains("ng-pristine")).toBe(true);
+      expect(input1.classes.contains("ng-pristine")).toBe(true);
+
+      input1.checked = true;
+      _.triggerEvent(input1, 'click');
+
+      expect(model.pristine).toEqual(false);
+      expect(model.dirty).toEqual(true);
+
+      input1.checked = false;
+      input2.checked = true;
+      _.triggerEvent(input2, 'click');
+
+      expect(input1.classes.contains("ng-dirty")).toBe(true);
+      expect(input2.classes.contains("ng-dirty")).toBe(true);
+      expect(input1.classes.contains("ng-pristine")).toBe(false);
+      expect(input1.classes.contains("ng-pristine")).toBe(false);
+    }));
   });
 
   describe('type="search"', () {