Outputting required field indicator for symfony forms - symfony1

I have a few forms configured in symfony. One things I need is to have an asterisk (*) or other indicator next to fields that are required. The fields are all set to required int he form framework, and return a "this field is required" error when the form is submitted, but I want an indicator before the form is submitted.
If there any way to do this without overriding the labels for each field manually?

Here's an automatic solution found in Kris Wallsmith's blog:
lib/formatter/RequiredLabelsFormatterTable.class.php, this will add a 'required' class to the labels of required fields
<?php
class RequiredLabelsFormatterTable extends sfWidgetFormSchemaFormatterTable
{
protected
$requiredLabelClass = 'required';
public function generateLabel($name, $attributes = array())
{
// loop up to find the "required_fields" option
$widget = $this->widgetSchema;
do {
$requiredFields = (array) $widget->getOption('required_fields');
} while ($widget = $widget->getParent());
// add a class (non-destructively) if the field is required
if (in_array($this->widgetSchema->generateName($name), $requiredFields)) {
$attributes['class'] = isset($attributes['class']) ?
$attributes['class'].' '.$this->requiredLabelClass :
$this->requiredLabelClass;
}
return parent::generateLabel($name, $attributes);
}
}
lib/form/BaseForm.class.php, this is the common base class for all the forms in your project:
protected function getRequiredFields(sfValidatorSchema $validatorSchema = null, $format = null)
{
if (is_null($validatorSchema)) {
$validatorSchema = $this->validatorSchema;
}
if (is_null($format)) {
$format = $this->widgetSchema->getNameFormat();
}
$fields = array();
foreach ($validatorSchema->getFields() as $name => $validator) {
$field = sprintf($format, $name);
if ($validator instanceof sfValidatorSchema) {
// recur
$fields = array_merge(
$fields,
$this->getRequiredFields($validator, $field.'[%s]')
);
} else if ($validator->getOption('required')) {
// this field is required
$fields[] = $field;
}
}
return $fields;
}
add the following few lines to BaseForm as well, in the __construct() method:
$this->widgetSchema->addOption("required_fields", $this->getRequiredFields());
$this->widgetSchema->addFormFormatter('table',
new RequiredLabelsFormatterTable($this->widgetSchema)
);
After all this, all your labels will have the required class, use whatever css you need to mark it to the user.

What about the simpler solution from the original cookbook - just a few lines in twig:
http://symfony.com/doc/2.1/cookbook/form/form_customization.html#adding-a-required-asterisk-to-field-labels

you can set the field's class as part of the constructor of the sfWidget
i.e.
$this->widgetSchema['form_field'] = new sfWidgetFormInput(array(), array('class' => 'required_field'));
Note: this is assuming you're not on the ancient sfForms (ala 1.0)
UPDATE
here is some CSS code from techchorus.net to show the required asterisk
.required
{
background-image:url(/path/to/your/images/dir/required-field.png);
background-position:top right;
background-repeat:no-repeat;
padding-right:10px;
}

I did it using Javascript:
$('form').find('select, input, textarea').each(function(){
if($(this).attr('required') == 'required'){
$label = $('label[for='+ $(this).attr('id') +']');
if($label.find('.required-field').length == 0){
$label.append('<span class="required-field">*</span>');
}
}
});

Related

How Unit Test angular material MatTableDataSource?

Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Setup the filter for a table
* #param dataTable data source to setup
*/
private setupFilter(dataTable: MatTableDataSource<Element>) {
dataTable.filterPredicate = (data: any, filter: string) => {
filter = filter.toLowerCase();
return data.name.toLowerCase().includes(filter)
|| data.description.toString().includes(filter);
};
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Checking control validation for edit inputs
* #param value Equals to ngmodel for the input
* #param column Equals to column name
*/
public editControlHasError(value: string, column: string): void {
if (column === 'name') {
this.errorInName.required = value === '';
this.errorInName.maxlength = value.length > Constants.MAX_LENGTH_NAME;
return;
}
this.errorInDescription.required = value === '';
this.errorInDescription.maxlength = value.length > Constants.MAX_LENGTH_DESCRIPTION;
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Methode that apply the table filter
* #param filterValue the filter value
*/
public applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Clear the filters value
*/
clearFilters() {
this.filter = '';
this.dataSource.filter = '';
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Method that loads a list of profiles to display on the rol select
*/
private loadProfiles() {
this.loaders.dataSource = true;
this.profilesService.getAllProfiles()
.pipe(
finalize(() => {
this.loaders.dataSource = false;
this.updateDOM();
})
)
.subscribe(
data => {
this.dataSource = new MatTableDataSource<Element>(data);
// getting properties from the object to sort the column from nested objects
this.dataSource.sortingDataAccessor = (obj, property) =>
this.getProperty(obj, property);
this.dataSource.sort = this.sort;
this.setupFilter(this.dataSource);
}
);
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Method that create a Profile
*/
public addProfile() {
for (const key in this.profileForm.controls) {
if (this.profileForm.controls[key] &&
this.profileForm.controls[key].value.toString().trim() === '') {
this.profileForm.controls[key].setValue('');
}
}
if (this.profileForm.valid) {
this.loaders.process = true;
const profile: Profile = new Profile();
profile.idProfile = 0;
profile.name = this.profileForm.controls.name.value.trim();
profile.description = this.profileForm.controls.description.value.trim();
this.profilesService.addProfile(profile).subscribe(
data => {
this.loaders.process = false;
this.profileForm.reset();
this.loadProfiles();
this.showModalAlert(data);
}
);
}
}
Some methods angular material, i need to unit test of each one, but i don't know how
/**
* Method that loads a profile for edit from the list
*/
public loadEditProfile(element: Profile) {
if (this.dataSource.data.some((e: any) => !!e.edit)) {
this.cancelEdit();
this.initErrorCheckers();
}
this.profileElementTmp = JSON.parse(JSON.stringify(element));
this.profileElementAux = element;
element.edit = true;
}
Some methods angular material, i need to unit test of each one, but i don't know how

Vaadin: open calendar on field focus for datefield

Vaadin widgets are simple and awesome! But they are also poorly configurable.
I need my DateField widget to open calendar on focus event. I didn't find that functionality in official Vaadin documentation. I found some 3rd party widget here, but it's compiled for Vaadin 7.7 and I use latest Vaadin (8.0.6). Also it has Joda-time 2.1 dependency which is highly undesirable in my project. So, is there any simple way to tune stock vaadin DateField widget to open it's calendar on field focus, or do I need to write my own component for that? Any help is appreciated.
As I was saying in my comment, as far as I know, currently the framework does not offer an implicit way to programmatically open the calendar popup. The same thing goes for some other components such as the grid editor, or the combo item list.
One quick workaround I can think of, is to add a javascript extension that registers focus listeners for all date fields, and clicks the button when a date field is focused. Please find below a sample.
P.S. If you only need to apply this to only some date fields, you can add IDs and pass them to the JS, where you'll do something like document.getElementById('myDateFieldId') instead of document.getElementsByClassName("v-datefield").
1) Layout with components
public class MyDateFieldComponent extends HorizontalLayout {
public MyDateFieldComponent() {
// basic setup
DateField fromDateField = new DateField("From", LocalDate.of(2011, Month.FEBRUARY, 6));
DateField toDateField = new DateField("To", LocalDate.of(2018, Month.FEBRUARY, 6));
setSpacing(true);
addComponents(fromDateField, toDateField);
// add the extension
addExtension(new CalendarFocusPopupOpenerExtension());
}
}
2) Extension - java/server side
import com.vaadin.annotations.JavaScript;
import com.vaadin.server.AbstractJavaScriptExtension;
#JavaScript("calendar-focus-popup-opener-extension.js")
public class CalendarFocusPopupOpenerExtension extends AbstractJavaScriptExtension {
public CalendarFocusPopupOpenerExtension() {
// call the bind function defined in the associated JS
callFunction("bind");
}
}
3) Extension - js/client side
window.com_example_calendar_CalendarFocusPopupOpenerExtension = function () {
this.bind = function () {
if (document.readyState === "complete") {
// if executed when document already loaded, just bind
console.log("Doc already loaded, binding");
bindToAllDateFields();
} else {
// otherwise, bind when finished loading
console.log("Doc nod loaded, binding later");
window.onload = function () {
console.log("Doc finally loaded, binding");
bindToAllDateFields();
}
}
};
function bindToAllDateFields() {
// get all the date fields to assign focus handlers to
var dateFields = document.getElementsByClassName("v-datefield");
for (var i = 0; i < dateFields.length; i++) {
addFocusListeners(dateFields[i]);
}
}
function addFocusListeners(dateField) {
// when focusing the date field, click the button
dateField.onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
// or when focusing the date field input, click the button
dateField.getElementsByTagName("input")[0].onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
}
};
4) Result
LATER UPDATE
A second approach could be to assign some IDs to your fields, and then check periodically to see when all are visible, and as soon as they are, bind the focus listeners.
1) Layout with components
public class MyDateFieldComponent extends HorizontalLayout {
public MyDateFieldComponent() {
// basic setup
DateField fromDateField = new DateField("From", LocalDate.of(2011, Month.FEBRUARY, 6));
fromDateField.setId("fromDateField"); // use id to bind
fromDateField.setVisible(false); // initially hide it
DateField toDateField = new DateField("To", LocalDate.of(2018, Month.FEBRUARY, 6));
toDateField.setId("toDateField"); // use id to bind
toDateField.setVisible(false); // initially hide it
// simulate a delay until the fields are available
Button showFieldsButton = new Button("Show fields", e -> {
fromDateField.setVisible(true);
toDateField.setVisible(true);
});
setSpacing(true);
addComponents(showFieldsButton, fromDateField, toDateField);
// add the extension
addExtension(new CalendarFocusPopupOpenerExtension(fromDateField.getId(), toDateField.getId()));
}
}
2) Extension - java/server side
#JavaScript("calendar-focus-popup-opener-extension.js")
public class CalendarFocusPopupOpenerExtension extends AbstractJavaScriptExtension {
public CalendarFocusPopupOpenerExtension(String... idsToBindTo) {
// send the arguments as an array of strings
JsonArray arguments = Json.createArray();
for (int i = 0; i < idsToBindTo.length; i++) {
arguments.set(i, idsToBindTo[i]);
}
// call the bind defined in the associated JS
callFunction("bind", arguments);
}
}
3) Extension - js/client side
window.com_example_calendar_CalendarFocusPopupOpenerExtension = function () {
var timer;
this.bind = function (idsToBindTo) {
// check every second to see if the fields are available. interval can be tweaked as required
timer = setInterval(function () {
bindWhenFieldsAreAvailable(idsToBindTo);
}, 1000);
};
function bindWhenFieldsAreAvailable(idsToBindTo) {
console.log("Looking for the following date field ids: [" + idsToBindTo + "]");
var dateFields = [];
for (var i = 0; i < idsToBindTo.length; i++) {
var dateFieldId = idsToBindTo[i];
var dateField = document.getElementById(dateFieldId);
if (!dateField) {
// field not present, wait
console.log("Date field with id [" + dateFieldId + "] not found, sleeping");
return;
} else {
// field present, add it to the list
console.log("Date field with id [" + dateFieldId + "] found, adding to binding list");
dateFields.push(dateField);
}
}
// all fields present and accounted for, bind the listeners!
clearInterval(timer);
console.log("All fields available, binding focus listeners");
bindTo(dateFields);
}
function bindTo(dateFields) {
// assign focus handlers to all date fields
for (var i = 0; i < dateFields.length; i++) {
addFocusListeners(dateFields[i]);
}
}
function addFocusListeners(dateField) {
// when focusing the date field, click the button
dateField.onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
// or when focusing the date field input, click the button
dateField.getElementsByTagName("input")[0].onfocus = function () {
dateField.getElementsByTagName("button")[0].click();
};
}
};
4) Result

Add text to bound values in Xamarin.forms

My modelView:
public string Status {
get { return _status; }
set {
if (value == _status) {
return;
}
_status = value;
OnPropertyChanged ("Status");
}
My View:
Label labelStatus = new Label {
TextColor = Color.Green,
FontSize = 20d
};
labelStatus.SetBinding (Label.TextProperty, "Status");
Then I want to present the status using something like:
string presentStatus = string.Format("Your status is {0}...", labelStatus);
Label yourStatus = new Label{Text=presentStatus}
But that doesn't really work. Nor does using
string presentStatus = string.Format("Your status is {0}...", SetBinding(Label.TextProperty,"Status"));
So how should I do to add my bound values with more text before presenting them for the user in a view.
If using XAML (which i don't), it seems possible according to: http://developer.xamarin.com/guides/cross-platform/xamarin-forms/xaml-for-xamarin-forms/data_binding_basics/
Xamarin Forms binding implementation doesn't currently allow complex binding scenarios like embedding bound text within static text.
There are two options
a. use multiple labels - one with the static text, one with the bound text
b. use a property on your ViewModel that concatenates the text for you
public string StatusText
{
get
{
return string.Format("Your status is {0}...", Status);
}
}
public string Status {
get { return _status; }
set {
if (value == _status) {
return;
}
_status = value;
OnPropertyChanged ("Status");
OnPropertyChanged ("StatusText");
}
You can do that in the BindingContextChanged-event:
labelStatus.BindingContextChanged += (sender, e) =>
{
// Here you can change the Text dynamically
// E.G. labelStatus.text = "Title: " + labelStatus.text
};

passing parameter/input data to custom elements in DART

I created a custom element, and want to send data / parameters to it:
my element code is:
class SaveBtn extends HtmlElement {
static final tag = 'save-button';
factory SaveBtn()=>new Element.tag(tag);
SaveBtn.created() : super.created() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
// Create a standard element and set it's attributes.
var btn = new ButtonElement();
...
btn.text= this.getAttribute('data-name');
shadow.nodes.add(btn);
Element launchElement(){
return (shadow);
}
}
}
The below code in the html file worked perfectly:
<save-button data-name='save orders'></save-button>
but what if I want to use the below code, what shall I adjust in my custom element code?
new SaveBtn('save orders')
This is another solution that worked with me before reading the posted answers, I liked #Gunter answer and will adapt it.
class SaveBtn extends HtmlElement {
static final tag = 'save-button';
factory SaveBtn()=>new Element.tag(tag);
var shadow, btn;
SaveBtn.created() : super.created() {
shadow = this.createShadowRoot();
btn = new ButtonElement()
..text="save"
..style.height= '20px'
..style.borderBottom='1px solid #D1DBE9';
btn.text = this.getAttribute('data-name');
shadow.nodes..add(label)..add(btn);
}
Element launchElement(name){
btn.text= name;
return (shadow);
}
}
and called the element as:
var btn=new SaveBtn()..launchElement('click me');
name is an optional argument. When you pass a value it is used for the text attribute of the button.
I pass it just to a field (name) in the elements class and set it to the the button in attached.
When you use data-xxx attributes you can use the dataset getter.
I also changed the other code a bit. I think attached is a better place to access attributes because then the element is already upgraded properly.
class SaveBtn extends HtmlElement {
static final tag = 'save-button';
factory SaveBtn([String name]) => (new Element.tag(tag) as SaveBtn)..name = name;
ButtonElement innerButton;
ShadowRoot shadow;
SaveBtn.created() : super.created() {
// Create a Shadow Root
var shadow = this.createShadowRoot();
// Create a standard element and set it's attributes.
innerButton = new ButtonElement();
shadow.nodes.add(innerButton);
}
String name;
#override
void attached() {
super.attached();
innerButton.text = name != null ? name : this.dataset['name'];
}
}
SaveBtn({String name, String width}) => (new Element.tag(tag) as SaveBtn)
..name = name
..style.width=width;
Below a solution proved to work.
factory SaveBtn() => new Element.tag(tag)
String name, width;
#override
void attached() {
super.attached();
innerButton.text = name != null ? name : this.dataset['name']
..style.width=width;
}
call the item as:
var btn = new SaveBtn()..name='save'..width='100%';
You can simply add a new constructor for this that sets the data-name attribute too:
class SaveBtn {
// ...
factory SaveBtn(String label) {
var btn = new Element.tag(tag);
btn.setAttribute('data-name', label); // Set properties/call methods here
return btn;
}
// ...
}

default constraints for property type

In Config.groovy one can specify default constraints that will apply to all properties, e.g.
grails.gorm.default.constraints = {
'*'(nullable: true)
}
Is there a way to specify default constraints for properties of a certain type? For example, if I want to add a (blank: false) constraint for all String properties is there a way to do that?
Not sure about adding a default constraint for a certain type, but in Programming Grails, Burt suggests a filter to handle blank fields:
class SiteFilters {
def filters = {
blankToNullAndTrim(controller: '*', action: '*') {
before = {
if (request.post) {
convertBlanksToNullsAndTrim(params)
}
true
}
}
}
private static void convertBlanksToNullsAndTrim(Map map) {
def keys = [] + map.keySet() // copy to avoid
//ConcurrentModificationException
for (name in keys) {
def value = map[name]
if (value instanceof String) {
value = value.trim()
if (value.length() == 0) {
map[name] = null // don't remove - explicity set to null
} else {
map[name] = value // update if trimmed
}
} else if (value instanceof Map) {
// recurse with empty nested param, e.g., "location":["id":""]
convertBlanksToNullsAndTrim value
}
}
}
}
With that there's no need to add blank:false.
Also, in Grails 2.3.x this behavior changed: by default all blank and empty Strings will be converted to null during data binding (configurable).

Resources