From 2b7531b9eb5b3a13083ca6d28083fa7c67f728db Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 20:09:00 +0000 Subject: [PATCH 1/8] how you expect an input to react when an initial value is set on the FormView --- examples/server/views/combined_validation.py | 3 +++ examples/test.sqlite | Bin 0 -> 172032 bytes 2 files changed, 3 insertions(+) create mode 100644 examples/test.sqlite diff --git a/examples/server/views/combined_validation.py b/examples/server/views/combined_validation.py index 8bed410..86c7c26 100644 --- a/examples/server/views/combined_validation.py +++ b/examples/server/views/combined_validation.py @@ -13,6 +13,9 @@ class SubscribeView(FormView): form_class = SubscribeForm success_url = reverse_lazy('form_data_valid') + def get_initial(self): + return {'first_name': 'james'} + def post(self, request, **kwargs): if request.is_ajax(): return self.ajax(request) diff --git a/examples/test.sqlite b/examples/test.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..ace7e9f4bdd2485d59b82dad0f4102375d8b0111 GIT binary patch literal 172032 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 ajxIw00uX=z1Rwwb2tWV=5P(3}3H(2Gz-QtB literal 0 HcmV?d00001 From 5a74e4552ee1cfa3ea3846266eeecbe8ea3043a2 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 20:24:28 +0000 Subject: [PATCH 2/8] issue introduced with angular 1.3+ when using new ng-model-options debounce --- examples/server/forms/combined_validation.py | 7 +++++++ examples/server/templates/base.html | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/server/forms/combined_validation.py b/examples/server/forms/combined_validation.py index b55b859..d08b1cc 100644 --- a/examples/server/forms/combined_validation.py +++ b/examples/server/forms/combined_validation.py @@ -10,7 +10,14 @@ class SubscribeForm(NgModelFormMixin, NgFormValidationMixin, subscribe_form.Subs scope_prefix = 'subscribe_data' form_name = 'my_form' + def get_widget_attrs(self, bound_field): + attrs = super(SubscribeForm, self).get_widget_attrs(bound_field) + attrs['ng-model-options'] = "{ debounce : { 'default' : 500, blur : 0 } }" + return attrs + def clean(self): if self.cleaned_data.get('first_name') == 'John' and self.cleaned_data.get('last_name') == 'Doe': raise ValidationError('The full name "John Doe" is rejected by the server.') return super(SubscribeForm, self).clean() + + diff --git a/examples/server/templates/base.html b/examples/server/templates/base.html index c362a88..769a569 100644 --- a/examples/server/templates/base.html +++ b/examples/server/templates/base.html @@ -48,7 +48,7 @@
{% block container %}{% endblock %}
- + {% block scripts %}{% endblock %} From a58569fb11f3917e55db27be109d3ba715d59f93 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 20:38:23 +0000 Subject: [PATCH 3/8] calling $commitViewValue fix --- examples/server/forms/combined_validation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/server/forms/combined_validation.py b/examples/server/forms/combined_validation.py index d08b1cc..1fc107a 100644 --- a/examples/server/forms/combined_validation.py +++ b/examples/server/forms/combined_validation.py @@ -9,12 +9,12 @@ class SubscribeForm(NgModelFormMixin, NgFormValidationMixin, subscribe_form.SubscribeForm): scope_prefix = 'subscribe_data' form_name = 'my_form' - + def get_widget_attrs(self, bound_field): attrs = super(SubscribeForm, self).get_widget_attrs(bound_field) attrs['ng-model-options'] = "{ debounce : { 'default' : 500, blur : 0 } }" return attrs - + def clean(self): if self.cleaned_data.get('first_name') == 'John' and self.cleaned_data.get('last_name') == 'Doe': raise ValidationError('The full name "John Doe" is rejected by the server.') From 4f3f61dc6e3a976d1595474a75f8c629f5105233 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 20:45:57 +0000 Subject: [PATCH 4/8] fix using $modelValue --- client/src/js/ng-django-forms.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/js/ng-django-forms.js b/client/src/js/ng-django-forms.js index d8d8bdc..0430b93 100644 --- a/client/src/js/ng-django-forms.js +++ b/client/src/js/ng-django-forms.js @@ -75,7 +75,10 @@ djng_forms_module.directive('ngModel', function() { break; default: if (field.defaultValue) { - modelCtrl.$setViewValue(field.defaultValue); + console.log('field.defaultValue',field.defaultValue) + console.log('setting $modelValue'); + modelCtrl.$modelValue = field.defaultValue; + console.log(modelCtrl) } break; } From abb87e665bc6f80efa12e8ea34b629e014a080d0 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 21:05:25 +0000 Subject: [PATCH 5/8] $commitViewValue fix --- client/src/js/ng-django-forms.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/js/ng-django-forms.js b/client/src/js/ng-django-forms.js index 0430b93..aa89d79 100644 --- a/client/src/js/ng-django-forms.js +++ b/client/src/js/ng-django-forms.js @@ -76,8 +76,8 @@ djng_forms_module.directive('ngModel', function() { default: if (field.defaultValue) { console.log('field.defaultValue',field.defaultValue) - console.log('setting $modelValue'); - modelCtrl.$modelValue = field.defaultValue; + modelCtrl.$setViewValue(field.defaultValue); + modelCtrl.$commitViewValue(); console.log(modelCtrl) } break; From 3c7a05a27b8a7af7bbe65013cb73c4cebefb33e9 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 22:17:35 +0000 Subject: [PATCH 6/8] proposed fix for #127 --- client/src/js/ng-django-forms.js | 49 ++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/client/src/js/ng-django-forms.js b/client/src/js/ng-django-forms.js index aa89d79..b58bb56 100644 --- a/client/src/js/ng-django-forms.js +++ b/client/src/js/ng-django-forms.js @@ -56,35 +56,30 @@ djng_forms_module.directive('djngError', function() { // Otherwise, the content of bound forms is not displayed, because AngularJS does not know about // the concept of bound forms and thus hides values preset by Django while rendering HTML. djng_forms_module.directive('ngModel', function() { - function restoreInputField(modelCtrl, field) { + function restoreInputField(field) { // restore the field's content from the rendered content of bound fields switch (field.type) { case 'radio': if (field.defaultChecked) { - modelCtrl.$setViewValue(field.defaultValue); + return field.defaultValue; } break; case 'checkbox': if (field.defaultChecked) { - modelCtrl.$setViewValue(true); + return true; } break; case 'password': // after an (un)successful submission, reset the password field - modelCtrl.$setViewValue(null); + return null; break; default: - if (field.defaultValue) { - console.log('field.defaultValue',field.defaultValue) - modelCtrl.$setViewValue(field.defaultValue); - modelCtrl.$commitViewValue(); - console.log(modelCtrl) - } + return field.defaultValue; break; } } - function restoreSelectOptions(modelCtrl, field) { + function restoreSelectOptions(field) { var multivalues = []; angular.forEach(field.options, function(option) { if (option.defaultSelected) { @@ -93,20 +88,18 @@ djng_forms_module.directive('ngModel', function() { if (field.multiple) { multivalues.push(option.value); } else { - modelCtrl.$setViewValue(option.value); + return option.value; } } }); if (field.multiple) { - modelCtrl.$setViewValue(multivalues); + return multivalues; } } - function restoreTextArea(modelCtrl, field) { - if (field.defaultValue) { - // restore the field's content from the rendered content of bound fields - modelCtrl.$setViewValue(field.defaultValue); - } + function restoreTextArea(field) { + // restore the field's content from the rendered content of bound fields + return field.defaultValue; } return { @@ -119,20 +112,34 @@ djng_forms_module.directive('ngModel', function() { var modelCtrl = ctrls[0], formCtrl = ctrls[1] || null; if (!field || !formCtrl) return; + + var defaultValue; + switch (field.tagName) { case 'INPUT': - restoreInputField(modelCtrl, field); + defaultValue = restoreInputField(field); break; case 'SELECT': - restoreSelectOptions(modelCtrl, field); + defaultValue = restoreSelectOptions(field); break; case 'TEXTAREA': - restoreTextArea(modelCtrl, field); + defaultValue = restoreTextArea(field); break; default: console.log('Unknown field type'); break; } + + if(angular.isDefined(defaultValue)) { + + modelCtrl.$setViewValue(defaultValue); + + if(angular.isObject(modelCtrl.$options) && + modelCtrl.$options.debounce) { + modelCtrl.$commitViewValue(); + } + } + // restore the form's pristine state formCtrl.$setPristine(); } From 50f132f4bc3460a0c765af9b78a7e2a5b1284e04 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sat, 29 Nov 2014 23:55:43 +0000 Subject: [PATCH 7/8] refactored ngModel extension to create default model on scope --- client/src/js/ng-django-forms.js | 40 +++++++++++++++------- examples/server/views/classic_subscribe.py | 3 ++ examples/server/views/client_validation.py | 3 ++ examples/server/views/model_scope.py | 3 ++ 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/client/src/js/ng-django-forms.js b/client/src/js/ng-django-forms.js index b58bb56..3f7d05e 100644 --- a/client/src/js/ng-django-forms.js +++ b/client/src/js/ng-django-forms.js @@ -55,7 +55,7 @@ djng_forms_module.directive('djngError', function() { // This directive overrides some of the internal behavior on forms if used together with AngularJS. // Otherwise, the content of bound forms is not displayed, because AngularJS does not know about // the concept of bound forms and thus hides values preset by Django while rendering HTML. -djng_forms_module.directive('ngModel', function() { +djng_forms_module.directive('ngModel', function($parse) { function restoreInputField(field) { // restore the field's content from the rendered content of bound fields switch (field.type) { @@ -101,6 +101,28 @@ djng_forms_module.directive('ngModel', function() { // restore the field's content from the rendered content of bound fields return field.defaultValue; } + + function processDefaultValue(scope, ngModelName, value) { + + var parts = ngModelName.split('.'), + prop = parts.pop(), + modelName = parts.join('.'), + fn = $parse(model !== '' ? model : prop), + model; + + if(modelName !== '') { + + fn = $parse(modelName); + model = fn(scope) || {}; + model[prop] = value; + fn.assign(scope, model); + + }else{ + + fn = $parse(prop); + fn.assign(scope, value); + } + } return { restrict: 'A', @@ -112,7 +134,7 @@ djng_forms_module.directive('ngModel', function() { var modelCtrl = ctrls[0], formCtrl = ctrls[1] || null; if (!field || !formCtrl) return; - + var defaultValue; switch (field.tagName) { @@ -129,24 +151,16 @@ djng_forms_module.directive('ngModel', function() { console.log('Unknown field type'); break; } - + if(angular.isDefined(defaultValue)) { - - modelCtrl.$setViewValue(defaultValue); - - if(angular.isObject(modelCtrl.$options) && - modelCtrl.$options.debounce) { - modelCtrl.$commitViewValue(); - } + processDefaultValue(scope, attrs.ngModel, defaultValue); } - - // restore the form's pristine state - formCtrl.$setPristine(); } }; }); + djng_forms_module.directive('validateMultipleFields', function() { return { restrict: 'A', diff --git a/examples/server/views/classic_subscribe.py b/examples/server/views/classic_subscribe.py index 87e101b..e262a30 100644 --- a/examples/server/views/classic_subscribe.py +++ b/examples/server/views/classic_subscribe.py @@ -9,3 +9,6 @@ class SubscribeView(FormView): template_name = 'subscribe-form.html' form_class = SubscribeForm success_url = reverse_lazy('form_data_valid') + + def get_initial(self): + return {'first_name': 'james'} diff --git a/examples/server/views/client_validation.py b/examples/server/views/client_validation.py index 3c9985c..05cc551 100644 --- a/examples/server/views/client_validation.py +++ b/examples/server/views/client_validation.py @@ -9,3 +9,6 @@ class SubscribeView(FormView): template_name = 'client-validation.html' form_class = SubscribeForm success_url = reverse_lazy('form_data_valid') + + def get_initial(self): + return {'first_name': 'james'} diff --git a/examples/server/views/model_scope.py b/examples/server/views/model_scope.py index a3e0b4a..52979b5 100644 --- a/examples/server/views/model_scope.py +++ b/examples/server/views/model_scope.py @@ -13,6 +13,9 @@ class SubscribeView(FormView): form_class = SubscribeForm success_url = reverse_lazy('form_data_valid') + def get_initial(self): + return {'first_name': 'james'} + def post(self, request, **kwargs): if request.is_ajax(): return self.ajax(request) From 513b095bbebd8bdd25e9d63a7203d5be3e07fd68 Mon Sep 17 00:00:00 2001 From: jamesrobb Date: Sun, 30 Nov 2014 13:08:37 +0000 Subject: [PATCH 8/8] change angular version to 1.2.3 --- examples/server/templates/base.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/server/templates/base.html b/examples/server/templates/base.html index 769a569..438d849 100644 --- a/examples/server/templates/base.html +++ b/examples/server/templates/base.html @@ -48,7 +48,7 @@
{% block container %}{% endblock %}
- + {% block scripts %}{% endblock %}