Skip to content

Commit 3fddacf

Browse files
committed
merge
2 parents 76d049f + 35adc7b commit 3fddacf

17 files changed

Lines changed: 260 additions & 140 deletions

File tree

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ python:
77
env:
88
- DJANGO=1.5.10 MIGRATE='true'
99
- DJANGO=1.6.10 MIGRATE='true'
10-
- DJANGO=1.7.4 MIGRATE='./manage.py migrate'
10+
- DJANGO=1.7.7 MIGRATE='./manage.py migrate'
1111

1212
install:
1313
- pip install -q Django==$DJANGO

client/src/js/ng-django-forms.js

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -149,63 +149,53 @@ djng_forms_module.directive('ngModel', function() {
149149
});
150150

151151

152+
// This directive is added automatically by django-angular for widgets of type RadioSelect and
153+
// CheckboxSelectMultiple. This is necessary to adjust the behavior of a collection of input fields,
154+
// which forms a group for one `django.forms.Field`.
152155
djng_forms_module.directive('validateMultipleFields', function() {
153156
return {
154157
restrict: 'A',
155158
require: '^?form',
156-
// create child scope for changed method
157-
scope: true,
158-
compile: function(element, attrs) {
159-
angular.forEach(element.find('input'), function(elem) {
160-
elem = angular.element(elem)
161-
elem.attr('ng-change', 'changed()');
162-
});
163-
164-
return {
165-
166-
post: function(scope, element, attrs, controller) {
167-
var formCtrl, subFields, checkboxCtrls = [];
168-
169-
scope.changed = function() {
170-
validate(true)
171-
}
172-
173-
function validate(trigger) {
174-
var valid = false;
175-
angular.forEach(checkboxCtrls, function(checkbox) {
176-
valid = valid || checkbox.$modelValue;
177-
if(checkbox.clearRejected) {
178-
checkbox.clearRejected();
179-
}
180-
});
181-
182-
formCtrl.$setValidity('required', valid);
183-
formCtrl.$setValidity('rejected', true);
184-
formCtrl.$message = ''
185-
186-
if (trigger && angular.isString(subFields)) {
187-
formCtrl[subFields].$dirty = true;
188-
formCtrl[subFields].$pristine = false;
189-
}
190-
}
191-
192-
if (!controller)
193-
return;
194-
formCtrl = controller;
195-
try {
196-
subFields = angular.fromJson(attrs.validateMultipleFields);
197-
} catch (SyntaxError) {
198-
subFields = attrs.validateMultipleFields;
199-
}
200-
angular.forEach(element.find('input'), function(elem) {
201-
if (subFields.indexOf(elem.name) >= 0) {
202-
checkboxCtrls.push(formCtrl[elem.name]);
203-
}
204-
});
159+
link: function(scope, element, attrs, formCtrl) {
160+
var subFields, checkboxElems = [];
205161

206-
validate();
162+
function validate(event) {
163+
var valid = false;
164+
angular.forEach(checkboxElems, function(checkbox) {
165+
valid = valid || checkbox.checked;
166+
});
167+
formCtrl.$setValidity('required', valid);
168+
if (event) {
169+
formCtrl.$dirty = true;
170+
formCtrl.$pristine = false;
171+
scope.$apply();
207172
}
208173
}
174+
175+
if (!formCtrl)
176+
return;
177+
try {
178+
subFields = angular.fromJson(attrs.validateMultipleFields);
179+
} catch (SyntaxError) {
180+
if (!angular.isString(attrs.validateMultipleFields))
181+
return;
182+
subFields = [attrs.validateMultipleFields];
183+
formCtrl = formCtrl[subFields];
184+
}
185+
angular.forEach(element.find('input'), function(elem) {
186+
if (subFields.indexOf(elem.name) >= 0) {
187+
checkboxElems.push(elem);
188+
angular.element(elem).on('change', validate);
189+
}
190+
});
191+
192+
// remove "change" event handlers from each input field
193+
element.on('$destroy', function() {
194+
angular.forEach(element.find('input'), function(elem) {
195+
angular.element(elem).off('change');
196+
});
197+
});
198+
validate();
209199
}
210200
};
211201
});
@@ -290,7 +280,7 @@ djng_forms_module.factory('djangoForm', function() {
290280

291281
return {
292282
// setErrors takes care of updating prepared placeholder fields for displaying form errors
293-
// deteced by an AJAX submission. Returns true if errors have been added to the form.
283+
// detected by an AJAX submission. Returns true if errors have been added to the form.
294284
setErrors: function(form, errors) {
295285
// remove errors from this form, which may have been rejected by an earlier validation
296286
form.$message = '';
@@ -351,4 +341,27 @@ djng_forms_module.factory('djangoForm', function() {
351341
});
352342

353343

344+
// This directive behaves similar to `ng-bind` but leaves the elements content as is, if the
345+
// value to bind is undefined. This allows to set a default value in case the scope variables
346+
// are not ready yet.
347+
djng_forms_module.directive('djngBindIf', function() {
348+
return {
349+
restrict: 'A',
350+
compile: function(templateElement) {
351+
templateElement.addClass('ng-binding');
352+
return function(scope, element, attr) {
353+
element.data('$binding', attr.ngBind);
354+
scope.$watch(attr.djngBindIf, function ngBindWatchAction(value) {
355+
// We are purposefully using == here rather than === because we want to
356+
// catch when value is "null or undefined"
357+
// jshint -W041
358+
if (value == undefined)
359+
return;
360+
element.text(value);
361+
});
362+
};
363+
}
364+
};
365+
});
366+
354367
})(window.angular);

djangular/forms/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from django.utils import six
66
from .angular_base import BaseFieldsModifierMetaclass, NgFormBaseMixin
77
from .angular_model import NgModelFormMixin
8-
if VERSION[0] == 1 and VERSION[1] >= 5:
8+
if VERSION[:2] >= (1, 5):
99
from .angular_validation import NgFormValidationMixin
10-
if VERSION[0] == 1 and VERSION[1] < 7:
10+
if VERSION[:2] < (1, 7):
1111
from .models import PatchedModelFormMetaclass as ModelFormMetaclass
1212
else:
1313
from django.forms.models import ModelFormMetaclass

djangular/forms/angular_base.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
class SafeTuple(SafeData, tuple):
2222
"""
23-
Used to bypass escaping of TupleErrorList by the ``conditional_escape`` function in Django's form rendering.
23+
Used to bypass escaping of TupleErrorList by the ``conditional_escape`` function in Django's
24+
form rendering.
2425
"""
25-
pass
2626

2727

2828
@python_2_unicode_compatible
@@ -137,12 +137,18 @@ def css_classes(self, extra_classes=None):
137137
elif isinstance(field_css_classes, (list, tuple)):
138138
extra_classes.update(field_css_classes)
139139
elif isinstance(field_css_classes, dict):
140-
for key in (self.name, '*',):
141-
extra_field_classes = field_css_classes.get(key)
142-
if hasattr(extra_field_classes, 'split'):
143-
extra_field_classes = extra_field_classes.split()
144-
extra_field_classes = set(extra_field_classes or [])
145-
extra_classes.update(extra_field_classes)
140+
extra_field_classes = []
141+
for key in ('*', self.name):
142+
css_classes = field_css_classes.get(key)
143+
if hasattr(css_classes, 'split'):
144+
extra_field_classes = css_classes.split()
145+
elif isinstance(css_classes, (list, tuple)):
146+
if '__default__' in css_classes:
147+
css_classes.remove('__default__')
148+
extra_field_classes.extend(css_classes)
149+
else:
150+
extra_field_classes = css_classes
151+
extra_classes.update(extra_field_classes)
146152
return super(NgBoundField, self).css_classes(extra_classes)
147153

148154
def as_widget(self, widget=None, attrs=None, only_initial=False):

djangular/static/djangular/js/django-angular.js

Lines changed: 61 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// AUTOGENERATED FILE - DO NOT EDIT!
2-
// django-angular - v0.7.11 - 2015-03-05
2+
// django-angular - v0.7.11 - 2015-03-21
33
// https://github.com/jrief/django-angular
44
// Copyright (c) 2015 Jacob Rief; Licensed
55
(function (angular, undefined) {
@@ -136,54 +136,50 @@
136136
}
137137
};
138138
});
139+
// This directive is added automatically by django-angular for widgets of type RadioSelect and
140+
// CheckboxSelectMultiple. This is necessary to adjust the behavior of a collection of input fields,
141+
// which forms a group for one `django.forms.Field`.
139142
djng_forms_module.directive('validateMultipleFields', function () {
140143
return {
141144
restrict: 'A',
142145
require: '^?form',
143-
scope: true,
144-
compile: function (element, attrs) {
146+
link: function (scope, element, attrs, formCtrl) {
147+
var subFields, checkboxElems = [];
148+
function validate(event) {
149+
var valid = false;
150+
angular.forEach(checkboxElems, function (checkbox) {
151+
valid = valid || checkbox.checked;
152+
});
153+
formCtrl.$setValidity('required', valid);
154+
if (event) {
155+
formCtrl.$dirty = true;
156+
formCtrl.$pristine = false;
157+
scope.$apply();
158+
}
159+
}
160+
if (!formCtrl)
161+
return;
162+
try {
163+
subFields = angular.fromJson(attrs.validateMultipleFields);
164+
} catch (SyntaxError) {
165+
if (!angular.isString(attrs.validateMultipleFields))
166+
return;
167+
subFields = [attrs.validateMultipleFields];
168+
formCtrl = formCtrl[subFields];
169+
}
145170
angular.forEach(element.find('input'), function (elem) {
146-
elem = angular.element(elem);
147-
elem.attr('ng-change', 'changed()');
148-
});
149-
return {
150-
post: function (scope, element, attrs, controller) {
151-
var formCtrl, subFields, checkboxCtrls = [];
152-
scope.changed = function () {
153-
validate(true);
154-
};
155-
function validate(trigger) {
156-
var valid = false;
157-
angular.forEach(checkboxCtrls, function (checkbox) {
158-
valid = valid || checkbox.$modelValue;
159-
if (checkbox.clearRejected) {
160-
checkbox.clearRejected();
161-
}
162-
});
163-
formCtrl.$setValidity('required', valid);
164-
formCtrl.$setValidity('rejected', true);
165-
formCtrl.$message = '';
166-
if (trigger && angular.isString(subFields)) {
167-
formCtrl[subFields].$dirty = true;
168-
formCtrl[subFields].$pristine = false;
169-
}
170-
}
171-
if (!controller)
172-
return;
173-
formCtrl = controller;
174-
try {
175-
subFields = angular.fromJson(attrs.validateMultipleFields);
176-
} catch (SyntaxError) {
177-
subFields = attrs.validateMultipleFields;
178-
}
179-
angular.forEach(element.find('input'), function (elem) {
180-
if (subFields.indexOf(elem.name) >= 0) {
181-
checkboxCtrls.push(formCtrl[elem.name]);
182-
}
183-
});
184-
validate();
171+
if (subFields.indexOf(elem.name) >= 0) {
172+
checkboxElems.push(elem);
173+
angular.element(elem).on('change', validate);
185174
}
186-
};
175+
});
176+
// remove "change" event handlers from each input field
177+
element.on('$destroy', function () {
178+
angular.forEach(element.find('input'), function (elem) {
179+
angular.element(elem).off('change');
180+
});
181+
});
182+
validate();
187183
}
188184
};
189185
});
@@ -312,6 +308,28 @@
312308
}
313309
};
314310
});
311+
// This directive behaves similar to `ng-bind` but leaves the elements content as is, if the
312+
// value to bind is undefined. This allows to set a default value in case the scope variables
313+
// are not ready yet.
314+
djng_forms_module.directive('djngBindIf', function () {
315+
return {
316+
restrict: 'A',
317+
compile: function (templateElement) {
318+
templateElement.addClass('ng-binding');
319+
return function (scope, element, attr) {
320+
element.data('$binding', attr.ngBind);
321+
scope.$watch(attr.djngBindIf, function ngBindWatchAction(value) {
322+
// We are purposefully using == here rather than === because we want to
323+
// catch when value is "null or undefined"
324+
// jshint -W041
325+
if (value == undefined)
326+
return;
327+
element.text(value);
328+
});
329+
};
330+
}
331+
};
332+
});
315333
}(window.angular));
316334
(function (angular, undefined) {
317335
'use strict';

0 commit comments

Comments
 (0)