#3512 closed Uncategorized (fixed)
Add "required" & "error" CSS classes to form rows in as_* methods
Reported by: | Owned by: | nobody | |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Normal | Keywords: | |
Cc: | waylan@…, real.human@…, Gonzalo Saavedra, liangent@…, andy@…, drackett@… | Triage Stage: | Accepted |
Has patch: | yes | Needs documentation: | yes |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Currently, there is no way to identify which fields have errors or are required with CSS. The patch below adds HTML classes to the containing block element for that purpose.
Therefore, using as_tr(), a field that is both required and contains an error would begin like so:
<tr class="error required">...
I have submitted three patches for consideration as I am unsure of whether we want to to allow people creating their own as_methods (through subclassing etc) to be able to add their own classes separate from the above.
See this thread for more details: http://groups.google.com/group/django-developers/browse_thread/thread/fbd0c8cfbf1b819b/
The three patches do not yet have tests (or at least the existing tests have not been adjusted) and I haven't even looked at docs. Maybe when a decision is made, I'll tackle that. Or if anyone else wants to...
Attachments (8)
Change History (46)
by , 18 years ago
Attachment: | html_class1.diff added |
---|
comment:1 by , 18 years ago
For html_class1.diff the example in the note should have been: <tr class="">
. Sorry about that.
by , 18 years ago
Attachment: | html_class3.diff added |
---|
Adds another argument to _as_html() but is easy to override and clean.
comment:2 by , 18 years ago
Needs documentation: | set |
---|---|
Needs tests: | set |
My guess is the docs and tests only need to be updated to reflect the new output, but I haven't got that far yet.
comment:3 by , 18 years ago
Hey Wayne check out http://code.djangoproject.com/ticket/3515 your idea is great but I needed these options on the actual fields, and to be included regardless of how I output the form. Also added css='myfield' support to all field types.
by , 18 years ago
Attachment: | html_class3.2.diff added |
---|
slightly improved, should use same logic for html_class2.diff if that is preferred
comment:4 by , 18 years ago
Triage Stage: | Unreviewed → Design decision needed |
---|
Perhaps this needs some sort of merge with #3515?
comment:5 by , 18 years ago
I strongly prefer this fix to the one suggested in #3515. There is a bug in the patch at line 122 though, it says:
class_list = html_class_list # Reset for each loop.
This does in fact not reset the list for each loop step, but results in "required" being appended over and over again. In my example code I tried I got class="required required required"
in one case :P
If this is changed to class_list=[]
everything is fine as far as I can see. I would very much like this patch to go into trunk.
comment:6 by , 18 years ago
So why did you prefer 3512 over 3515? Personally, I've found it essential to control CSS class names on a per form element basis, otherwise you can't control sizes/layout etc and also for script handlers etc. The auto generated forms aren't any use to me either except for pre-design functionality testing.
comment:7 by , 18 years ago
Because with 3512 I can set styles on the label or the actual form input at will with "label .required" and "input .required" for example. With 3515 the only way to set a style on the label tag is by traversing the DOM, since only the input control got the CSS class set.
With this patch you CAN set css styles on a per form basis, just not in the model. As long as you on the form tag itself put an ID, you can individually control the styling of any item in the form with the CSS selector, for example: "#id_my_poll_form #id_title label { background: yellow; }" This will only set the color of labels inside items with the id "id_title" that are in turn inside a form "id_my_poll_form". This prevents unreasonable leakage across the MVC layers, unlike 3515 where I have to set CSS classes in the model where they really don't belong.
comment:8 by , 18 years ago
The latest patch in this sequence has a bug that would need to be fixed: using mutable objects (such as []) as default arguments to functions is wrong. They are created once at import time and exist in the module's scope (not the function body). So if you accidently change them in place, the changes just accumulate each time the function is called.
This is why the bug in comment 5 is occurring (because it is assinging, by reference, a module-level object). Pass in a default of None and check it inside the function body. If the arg is None, assign an empty list to it.
I'm still trying to make sense of all the differences between this #3515 at the moment, but I wanted to note the problem while I remember it.
comment:9 by , 18 years ago
Thanks for the tip mtredinnick. I was wondering how scoping & instancing works in Python (I'm new).
Also I agree with boxed too. I've since realised I don't like the MVC leakage my CSS patch encourages. Gets a bit long winded in the CSS but that's just unavoidable MVC overhead. One suggestion though, redo 3512 at the lower level so it works for all forms not just the as_* ones, which I rarely find myself using.
comment:10 by , 18 years ago
IMO anyone who says having the class names directly on the form elements gives them more control needs to brush up on their css skills. Given the following html:
<li class="required"><label><input...></label></li>
I can do any of the following:
# style the wrapping block with .required {...} # style the label .required label {...} # style the form element .required input {...}
They're called "Cascading Style Sheets" for a reason. Remember there is only one form element per wrapping block. I could see a problem if that wasn't the case, but it is.
With #3515's approach, if you want to style the wrapping block element (li, tr, p) or the label you can't. I understand some people may not be using the as_methods and thats why they like 3515, but if they're building their own html, then IMO they should be building their own html.
comment:11 by , 18 years ago
And actually, the bug is that class_list
should be creating a copy of html_class_list
.
comment:12 by , 18 years ago
We're getting wires crossed - I don't think anyone here lacks CSS understanding.
- The reason 3515's CSS control is bad is because of MVC leakage; although it's convenient, model is perhaps not the cleanest place for CSS definition
- #id_ CSS selectors can be used to control individual field sizes, styles etc
- Another alternative is to make a css class name filter for templates, I'll think some more and post thoughts about that later
- 3512 is the more MVC-compliant approach but needs implementing for all output methods not just the as_ functions
Nice work people now lets finish it off and hopefully get it into trunk.
comment:13 by , 18 years ago
We're getting wires crossed - I don't think anyone here lacks CSS understanding.
- The reason 3515's CSS control is bad is because of MVC leakage; although it's convenient, model is perhaps not the cleanest place for CSS definition
- #id_ CSS selectors can be used to control individual field sizes, styles etc
- Another alternative is to make a css class name filter for templates, I'll think some more and post thoughts about that later
- 3512 is the more MVC-compliant approach but needs implementing for all output methods not just the as_ functions
Nice work people now lets finish it off and hopefully get it into trunk.
by , 18 years ago
Attachment: | html_class4.diff added |
---|
fixing bug in previous patch, adding tests and fixing docs
comment:14 by , 18 years ago
Needs documentation: | unset |
---|---|
Needs tests: | unset |
Simon, I disagree that this specific ticket needs to implement this new behaviour for all output methods. IMO, it's ready to go.
If you're after fine-grained then you can do this yourself (by testing form[fieldname].errors
and form[fieldname].field.required
) or with a new filter like you suggested.
comment:15 by , 18 years ago
For those who aren't using the as_methods(), you can still check if a field is required in the template, much like you can check that a field has errors:
{% for boundfield in form %} {% if boundfield.errors %} do stuff... {% endif %} {% if boundfield.field.required %} do stuff... {% endif %} {% endfor %}
We could always add a 'required' property to the BoundField class, but why? Here it is anyway (Allowing one to do {% if boundfield.required %}
):
def _required(self): "Returns True if this BoundField is required." return self.field.required required = property(_required)
Whether that little patch is applied or not, those of you building your own forms can generate whatever html you want without any additional patches and that is why this patch only affects the as_methods(). Yes, if you want a class attribute on a field element itself, you have to manually build the entire field element (with boundfield.name
, boundfield.data
, boundfield.label
etc) but isn't that the way it should be for those who want such fine grained control as to assign custom classes to individual elements in the templates?
Note: I'm posting this partially as a note to myself. I figured this all out a month ago when I wrote the patches, but promptly forgot. Following the above discussion, I dug in again only to realize I was repeating myself. D'oh.
comment:16 by , 18 years ago
... And I see SmileyChris made the same point in less words while I was typing that. Sorry for the repitition.
Nice work SmileyChris. I'd say your latest patch is ready to go as well.
Oh and Simon,
"We're getting wires crossed - I don't think anyone here lacks CSS understanding."
Your previous comment would appear otherwise:
"Personally, I've found it essential to control CSS class names on a per form element basis, otherwise you can't control sizes/layout etc"
If I misunderstood you, sorry about that, but between that comment and some in the original thread on the mailling list, I figured I'd clear things up once and for all.
comment:17 by , 18 years ago
Cc: | added |
---|
i would like to see something similar to the old css classes that were applied to actual form elements. with oldforms we had .vPasswordField, .vEmailField, .vIntegerField, etc. that was great, as it allowed you to set smaller fields for numerical data, or larger fields for email data.
in a pinch i'd accept simplified classes based on the form field type, not the model field type. e.g. .text, .button, .checkbox, .radio, and any other types of form elements specified with the input tag. this is helpful due to some browsers lacking the more specific selectors and therefore being unable to distinguish between a checkbox or a text input.
i'd also like to see an "optional" class applied to fields that are blank=True and/or null=True. if required/error/optional must go on the containing p, tr, or td tags, i'd like to see them renamed to something a little more obscure or specific. there may be many people out there who already have generic required/error classes which are used in p and table tags but are not actually related to forms. if the classes are assigned to label or actual form elements, you know it's attached to a form. otherwise there may be some collission.
comment:18 by , 18 years ago
oh, and i agree that at least some kind of css class needs to be attached to every actual html form field tag - input, select, textarea - as these may be output individually without generating the entire p or li or tr around a label and an input, select, or textarea.
comment:19 by , 18 years ago
mrmachine, you're getting rather sidetracked from this ticket. If you want to suggest other changes (even if they are similar), please open a new ticket ;)
comment:21 by , 18 years ago
See also #3686, which aims to add the classes back to the label
and input
tags, which is how Django currently does things.
by , 18 years ago
Attachment: | html_class4.3.diff added |
---|
add updated tests for modeltests.model_forms too
comment:22 by , 17 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Closing in favor of #3515.
comment:23 by , 17 years ago
Patch needs improvement: | set |
---|---|
Resolution: | duplicate |
Status: | closed → reopened |
Summary: | [patch] Add HTML classes to fields in newforms as_methods: "required" & "error" → [patch] Add "required" & "error" CSS classes to form rows in as_* methods |
After talking with ubernostrum, we came to the conclusion that this is not a direct duplicate
Because of their different tacts (independent approaches), I think it is best to leave them both open for a design decision even though they are attempting to solve the same problem.
#3515 is about attaching the class information directly to the HTML widget
#3512 is about attaching the class information to the HTML row (which you could then use to style the label or widget)
Tests need updating now that the newform tests have been split up. But I wouldn't bother doing that until I actually got a confirmation on this ticket or it'll just rot again.
follow-up: 25 comment:24 by , 17 years ago
Problem with this one, is it applies only to the as_ul etc which aren't useful in real world applications.
Newforms needs built-in, object level row *and* fieldset support. Then, we can talk about CSS classing rows and fieldsets.
comment:25 by , 17 years ago
Replying to Simon Litchfield:
Problem with this one, is it applies only to the as_ul etc which aren't useful in real world applications.
It only needs to apply to the helper methods because if you're using low level methods, then you can already do this.
Just test form[fieldname].errors
and
form[fieldname].field.required
follow-up: 27 comment:26 by , 17 years ago
It only needs to apply to the helper methods because if you're using low level methods, then you can already do this.
Yes, but what a mess of a template we end up with. The PHP and .NET guys would be laughing at us.
comment:27 by , 17 years ago
Replying to Simon Litchfield:
It only needs to apply to the helper methods because if you're using low level methods, then you can already do this.
Yes, but what a mess of a template we end up with. The PHP and .NET guys would be laughing at us.
If you're silly enough not to abstract it off to a helper method of your own, then they deserve to laugh ;) My point was that it's already possible. And aside from that, the current patch in #3515 shouldn't be attaching presentation information to the Field
class - that's what the Widget
class is for.
Anyway, I brought this up on django-dev again, let's discuss it there.
comment:28 by , 17 years ago
Think that's my point really, users shouldn't have to abstract newforms for such basic functionality. How many hoops should a user have to go through, for such simple functionality. Without row and fieldset support, newforms is half baked.
comment:29 by , 17 years ago
Summary: | [patch] Add "required" & "error" CSS classes to form rows in as_* methods → Add "required" & "error" CSS classes to form rows in as_* methods |
---|---|
Triage Stage: | Design decision needed → Accepted |
I'm almost sure that the spirit of the as_* methods is, precisely to avoid to use a template to print all fields. Having to do such template to have the error & required attributes seems a bit... non-DRY at all.
Moving to accepted. But the patch still needs to be updated.
comment:30 by , 16 years ago
Needs documentation: | set |
---|---|
Patch needs improvement: | unset |
Ok, here's my new take. Fully backwards compatible now.
Forms have two new attributes: error_html_class
and required_html_class
(both set to None
by default)
When you set them, your error / required rows get given the html class. Simple. Effective. Bam.
by , 16 years ago
comment:31 by , 16 years ago
Cc: | added |
---|
comment:34 by , 15 years ago
Cc: | added |
---|
comment:35 by , 15 years ago
Cc: | added |
---|
comment:36 by , 15 years ago
Cc: | added |
---|
comment:37 by , 15 years ago
Resolution: | → fixed |
---|---|
Status: | reopened → closed |
comment:38 by , 13 years ago
Cc: | removed |
---|---|
Easy pickings: | unset |
Severity: | → Normal |
Type: | → Uncategorized |
UI/UX: | unset |
Simple solution, easy to override, but could result in
<tr class="">