How to change Django NullBooleanField widget application wide? - django-forms

I would want to display all NullBooleanFields in my application as radio buttons. What's the best way to do it?
Following template or something similar would be ideal. Just to allow rich styling and tone-of-voice different from plain "Yes/No/Unknown".
'''<li class="field-%s">
<label class="%s" title="%s">%s</label>
<label class="y"><input type="radio" name="%s" value="1" %s /> %s</label>
<label class="n"><input type="radio" name="%s" value="0" %s /> %s</label>
<label class="e"><input type="radio" name="%s" value="" %s /> %s</label>
</li>
''' % (
field,
field, help text, verbose_name,
field, y, y_label,
field, n, n_label,
field, e, e_label
)

In the end I figured that setting widgets to RadioSelect one by one was less code even though I have a lot of NullBooleanFields. The <ul> producted by RadioSelect widget is enough structure to style on, even though it requires CSS3 selectors.
Not DRY, but less hassle. One needs to be pragmatic and move on.
If someone could provide code to change the default widget for NullBooleanField from NullBooleanSelect to RadioSelect on the forms.py level, I'd happily accept the answer.

I just implemented a custom widget to do this:
class YesNoNARadioSelect(widgets.Widget):
CHOICES=((True,'Yes'),(False,'No'),(None,'N/A'))
def render(self,name,value,attrs=None):
s=[]
for c in self.CHOICES:
extraAttrs=attrs.copy()
extraAttrs.update(dict(type='radio',name=name,value=c[0]))
if value==c[0]: extraAttrs['checked']='checked'
extraAttrs=self.build_attrs(extraAttrs)
s.append(format_html('<label><input {}/>{}</label>',flatatt(extraAttrs),c[1]))
return S(''.join(s))
Seems to work for me, although I'd like to hear of anything that I'm doing wrong with it.

Related

vee-validate 3 optional address fields but one is required

I'm using vee-validate form validation and I have 3 address fields:
House Number
House Name
Flat Number
All 3 are optional because an address may only have 1, but I need the user to fill in at least one. So I can't make any of them required, and the documentation for cross field validation only handles putting specific validation on a single or multiple fields:
https://logaretm.github.io/vee-validate/advanced/cross-field-validation.html#targeting-other-fields
What is the best way of handling this? I'm no stranger to custom validation rules in my project, I just don't understand the approach here.
Thanks.
<div class="flex flex-wrap pb-2">
<FormTextInput
name="addressBuildingNo"
v-model="value.buildingNo"
type="text"
:label="$t('formFields.addressBuildingNo')"
placeholder="e.g 10"
:hint="$t('formHints.optional')"
/>
<FormTextInput
name="addressFlatNo"
v-model="value.flatNo"
type="text"
:label="$t('formFields.addressFlatNo')"
:hint="$t('formHints.optional')"
/>
<FormTextInput
name="addressBuildingName"
v-model="value.buildingName"
type="text"
:label="$t('formFields.addressBuildingName')"
:hint="$t('formHints.optional')"
/>
</div>
Wrap each one in a ValidationProvider and set the required rule on each to be that it's required if neither of the other two are filled out. So the first one would look like this:
<ValidationProvider :rules="{ 'required': (!value.buildingName && !value.flatNo)">
<FormTextInput
name="addressBuildingNo"
v-model="value.buildingNo"
type="text"
:label="$t('formFields.addressBuildingNo')"
placeholder="e.g 10"
:hint="$t('formHints.optional')"
/>
</ValidationProvider>
If you want more complicated validation, you can also write cross-field validators for each one that check things more specifically (following the docs you pointed out already). See a simplified example here: https://codesandbox.io/s/veevalidate-30-cross-field-optional-3dzxd
In the end I just made a hidden field with the value being a combination of all 3 fields.
<FormTextInput name="addressBuilding" type="hidden" v-model="compBuildingValue" rules="required" />
compBuildingValue() {
return `${this.value.buildingNo.trim()}${this.value.flatNo.trim()}${this.value.buildingName.trim()}`
}

React-Boostrap ToggleButtonGroup onChange not working

It seems the onChange is still broken (refer to similar question here).
The onChange will fire however you cannot use event.target.value as the event.target is on a parent of the element with the value attribute. For example, I have something like this:
<ToggleButtonGroup type="radio" name="detect" defaultValue={1} onClick={event => this.onInputMethodChange(event.target)}>
<ToggleButton value={1}>Translate</ToggleButton>
<ToggleButton value={2}>Detect</ToggleButton>
</ToggleButtonGroup>
when I console.log(event.target) I get a label element but the value is on the input element.
<label>
<input value="2" >
</label>
Is there a way to get this input value? It's not ideal but I could at least work with it. Thanks!

How do i match the value which has a radio button checked

I have a list of similar looking DIVs without any Div ID, except one has a check box checked and others doesn't. What i need is to find the value from a child tag only if a radio button is selected.
Below is a simpler version of my code.
<div class = "XYZ">
<input type="radio" checked>
<input type="hidden" value="This is a great thing 1">
</div>
<div class = "XYZ">
<input type="radio">
<input type="hidden" value="This is a great thing 2">
</div>
Result needed is
This is a great thing 1
Unfortunately the source code cannot be changed.
Your xpath should look for a div that contains the checked input and to get the value for the one that has value attribute.
First selector returns the input, the second returns the value.
//div[.//input[#checked]]/input[#value]
//div[.//input[#checked]]/input/#value
As an alternative you can use the following sibling:
//input[#checked]/following-sibling::input
If you want to also use the class of the parent div:
//div[#class='XYZ']/input[#checked]/following-sibling::input

Angular2 template based form validation doesn't work

I'm currently trying to add validation to an angular 2 form, but for some reason I can't get my submit button to disable when the required fields are not filled in.
Here is the code of my form template:
<h1 md-dialog-title>{{title}}</h1>
<form #formCtrl="ngForm">
<md-dialog-content>
<md-input-container>
<input #name md-input placeholder="Name" value="" name="name" focused required>
</md-input-container>
<br />
<md-select #inputtype placeholder="Input type" name="inputtype">
<md-option *ngFor="let inputtype of inputtypes" [value]="inputtype.id">
{{inputtype.name}}
</md-option>
</md-select>
</md-dialog-content>
<md-dialog-actions>
<button type="submit" md-raised-button color="primary" [disabled]="!formCtrl.form.valid">Create</button>
</md-dialog-actions>
</form>
According to several examples, this should work, however the button is never disabled. I've also tried "!formCtrl.valid", also to no avail.
I've tried using non-material design input fields thinking maybe that would be the issue, but it still won't work.
I then tried copy/pasting the following simple example into my application, and even that won't work at all:
http://blog.angular-university.io/introduction-to-angular-2-forms-template-driven-vs-model-driven/
Any ideas as to what might prevent it from working correctly?
Assuming you are using a newer release than Angular 2 final:
You need to add ngModel, which binds the form value based on the name attribute’s value. In your case one is name="inputtype" the other is name="name". So you need to add ngModel to bind the values, and your form should work as you wish! :)
So the following should work (removed a bit of noise from code):
<form #formCtrl="ngForm" (ngSubmit)="save(formCtrl.value)"> //whatever your submit method is
<md-dialog-content>
<md-input-container>
<input md-input name="name" required ngModel>
</md-input-container>
<md-select name="inputtype" required ngModel>
<md-option *ngFor="let inputtype of inputtypes" [value]="inputtype.id">
{{inputtype.name}}
</md-option>
</md-select>
</md-dialog-content>
<md-dialog-actions>
<button type="submit" md-raised-button color="primary" [disabled]="!formCtrl.form.valid">Create</button>
</md-dialog-actions>
</form>
Don't remember when this was introduced, this should be found somewhere in the changelogs which can be useful to have a look at once in a while, since Angular is constantly tweaking things almost in every release. So following that will keep you updated with changes and syntax :)

mark only one checkbox?

I have a problem with checkbox. I have a list of checkbox, and I want to mark only one check and unmark other.
I want do that this in the same view , is it posible?
How can I do that?
<div><input type="checkbox" id="<%= id %>" onchange='submit();'/> </div>
thanks
Sounds like you really need a radio button instead. Radio buttons are mutually exclusive if you give them the same name:
<input type="radio" name="something" ... />
<input type="radio" name="something" ... />
If you really want checkboxes you will have to write some JavaScript logic.
Use radio buttons, not checkboxes.
<div>
foreach (var foo in model.Foos) {
<input type="radio" name="foo" id="foo_#foo.Id" value="#foo.Id" />
<label for="foo_#foo.Id">#foo.Value</label> <br />
}
</div>
Something like that should create a list of radio buttons.
Also, why are you submitting when the selection is changed? You should be using jQuery to do any selection-based manipulation to the page on the client side.
You could use jQuery. on document.Ready you'll have to bind a change event on checkboxes to some function, then in your function you want to reset all other checkboxes. That's assuming you don't want to use radio buttons as suggested above.

Resources