I am wanting to do a date of birth composite drop-down for date of birth (i.e. three drop-downs - one for day, one for month, one for year). Helpfully, ZF2 comes with this element built in, called DateSelect
Here is how I am adding it to the form:
$this->add([
'name' => 'date_of_birth',
'type' => 'DateSelect',
'attributes' => [
'required' => true,
'value' => date('Y-m-d', strtotime('18 years ago')),
],
'options' => [
'label' => 'Date of Birth',
'max_year' => date('Y', strtotime('18 years ago')),
],
]);
To render the form I am doing:
echo $this->form($form);
Anyway, the day element is being rendered in j format (i.e. day of the month without leading zeros 1 to 31).
How do I tell the element to render the day in d format (i.e. day of the month, 2 digits with leading zeros 01 to 31)?
I have check source code from Zend\Form\Element\DateSelect and it's view helper Zend\Form\View\Helper\FormDateSelect. The rendering date is on view helper, but it didn't use date('j'). It use IntlDateFormatter to format date, and it will output date format based on locale date format pattern given.
https://github.com/zendframework/zend-form/blob/release-2.2.0/src/View/Helper/FormDateSelect.php#L90
So, the solution we should pass the locale date format that use two digits day (dd). For country date format list, can be check here
https://en.wikipedia.org/wiki/Date_format_by_country
Based on the date format on list above, India use DD-MM-YY as date format. we can use this locale to get two digit day format,.
So, please use this on your view helper
echo $this->formDateSelect($form->get('date_of_birth'), IntlDateFormatter::MEDIUM, 'en_IN');
The view helper Zend\Form\View\Helper\FormDateSelect has a function getPattern that generates the patten by using the IntlDateFormatter class:
$intl = new IntlDateFormatter($this->getLocale(), $this->dateType, IntlDateFormatter::NONE);
$this->pattern = $intl->getPattern();
There did not appear to be any method of setting a pattern at element level, so I have extended this view helper allowing me to specify my own pattern:
<?php
namespace RPK\Form\View\Helper;
use Zend\Form\View\Helper\FormDateSelect as ZendFormDateSelect;
class FormDateSelect extends ZendFormDateSelect
{
/**
* Parse the pattern
*
* #param bool $renderDelimiters
* #return array
*/
protected function parsePattern($renderDelimiters = true)
{
//Replace `day` value of "d" with "dd"
$pattern = parent::parsePattern($renderDelimiters);
if($pattern['day'] === 'd') {
$pattern['day'] = 'dd';
}
return $pattern;
}
}
Very basically, this takes the returned pattern array (['day'=>'d', 'month' => 'MMMM', 'year' => 'yyyy']), checks if the value of day is a single letter "d" and, if so, replaces it with a double-d.
Related
We are having an issue where, in one of our Kendo charts we are developing to display some weekly data. The JSON that we're sending to the view looks like:
[
{"WeekofYear":45,"Value":96.08,"WeekBeginDate":"\/Date(1415422800000)\/"},
{"WeekofYear":46,"Value":97.40,"WeekBeginDate":"\/Date(1416027600000)\/"},
{"WeekofYear":47,"Value":96.50,"WeekBeginDate":"\/Date(1416632400000)\/"},
{"WeekofYear":48,"Value":93.93,"WeekBeginDate":"\/Date(1417237200000)\/"},
{"WeekofYear":49,"Value":96.76,"WeekBeginDate":"\/Date(1417842000000)\/"},
{"WeekofYear":50,"Value":94.50,"WeekBeginDate":"\/Date(1418446800000)\/"}
]
The dates in the JSON represent the date on each Saturday of the week in question. However, when we render the graph, it displays the date from the Sunday of the week instead, as displayed in the screenshot.
Chart Screenshot
We are using the following code in the Razor engine to generate the chart:
#(Html.Kendo().Chart<Dashboard.Models.CentralScheduling>()
.Name("CallsAnswered")
.Title("% of Calls Answered")
.Legend(legend => legend.Visible(false))
.DataSource(dataSource => dataSource
.Read(read => read.Action("CentralScheduling", "Dashboard").Data("filterStatusData")))
.Series(series =>
{
series.Line(d => d.Value)
.Tooltip(t => t.Visible(true).Template("#=value#%"));
})
.CategoryAxis(axis => axis
.Categories(model => model.WeekBeginDate) //WeekBeginDate holds the date at the end of the week for this particular chart
.Labels(labels => labels.Format("MM/dd/yyyy")
.Rotation(-60)
)
)
.ValueAxis(axis => axis
.Numeric().Labels(labels => labels.Format("{0}%"))
.Max(100)
)
.SeriesColors("#3aafff","#ffb800","#a7008f","#99c900","#FF0000", "#002060")
)
The filterStatusData function sets a flag that we use in the controller to generate the JSON for the calling chart.
I am at a loss to explain why a different date is being chosen for the chart rather than the one that we are supplying.
An option - this is comming from Telerik - is to pass the date as a string from the server instead of a .Net DateTime object. The client will parse it just like it does a date object. Use this format "yyyy-mm-dd HH:MM"
so your json would be something like:
[
{"WeekofYear":45,"Value":96.08,"WeekBeginDate":"2014-12-16 07:00"},
...
I develop an application in Ruby on Rails 4 with TimeZone per request.
I want to use a datetime picker (http://xdsoft.net/jqplugins/datetimepicker/) in my application to replace the default Simple_form datetime input (5 combo-boxes...).
For this kind of datetime picker (I search for others, it's the same), in my view, I have to use a "string" field, like this :
<%= f.input :done_at, as: :string, input_html: { :data => { :behaviour => "datetimepicker" } } %>
When I post the form, Rails take care of the timezone and store in the database the time in UTC.
For example, I put "2014-03-14 19:45:07" (local time is Paris, so UTC +0100) in the field, and I have "2014-03-14 18:45:07" in the database, in UTC. It's correct.
But when I want to edit the information, Rails fill in the field with a wrong time. The offset timezone is lost and I have "2014-03-14 18:45:07" in the field (the UTC time), so 1 hour before the correct time.
How can I have the correct time taking care of the user timezone ? (not in UTC)
I tried the solution found on http://jessehouse.com/blog/2013/11/15/working-with-timezones-and-ruby-on-rails/ to override the display of dates, but it doesn't work.
def done_at
super.in_time_zone(time_zone) if super && time_zone
end
If in my view, I put #action.done_at, the time is correct but not in the field.
Thanks,
Fred
Set the value of the input explicitly. You can move #object.done_at.in_time_zone(time_zone) to a helper if you want
<%= f.input :done_at, as: :string, input_html: { :data => { :behaviour => "datetimepicker" }, :value => #object.done_at.in_time_zone(time_zone).strftime('%d-%m-%Y %H:%M') } %>
all,
Am new to RoR and hence needed some guidance w.r.t Date field.
Background:
1 > I create a model object using rails generate scaffold <Model> name:string remainderDate: date
2 > Now when I have deployed the model to DB using rake db:migrate and on opening the URL: localhost:3000/<Model>s/new, the displayed date field is in the format YYYY MM DD, all 3 separate fields with dropdown with
YYYY values >=2006 and <=2016
MM values >= January and <= December (obvious)
DD values >= 1 and <=31
Question 1:
1> Where is the code for setting the values to these fields?
2> Can I change the format to MM DD YYYY?
3> Can I restrict the values being added to the list? i.e. for the current year 2011, only months starting from April should be shown and only dates starting current day should be shown
4> Where can I change the display text for the new form? I opened up new.html.erb and could not understand where the display text is set. I also opened up _form.html.erb and could not locate where necessary changes can be done?
Take a look at the syntax for date_select:
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-date_select
In your form you would have something like this:
<%= f.date_select :remainderDate, {:order => [:month, :day, :year],:prompt => true, :start_year => Time.now.year, :end_year => 2016} %>
So answers to your quenstions:
1/ as Wes answered
2/ the :order option in my example
3/ your can only restrict the year, not the months or dates with the options as you see with start_year and end_year in the example. You coud restrict further using validations in your model.
4/ what exactly do you mean with "the display text for the new form"? Do you mean the display text for the date field? That would be next to the <%= f.label %>
Regarding formats of the date field you want to pass the string in the way rails already is because mysql accepts it without modification. That said you can certainly change how the user enters the data on the form for a new record. Look for the view code in
app/views/<model>/_form.html.erb
I need to have a start and end time widget on a form.
i.e. the user selects a date and then selects the start and end time.
In the standard date widget, you can select a date and a time, however I need to be able to select a finish time too.
Have any of you done it before?
I could create 3 separate widgets:
Date
Start Time
End Time
When the form is saved, I'll do an update on the object to combine all values into one. For example, I'll get the date and add the start time to it and then save to the field "start_date" and then I'll get the date and add the end time to it and then save to the field "end_date". It does however seem a very long winded way to do something which should be fairly trivial for a form framework.
Is this how you'd do it? Thanks guys!
I think what you want to want achieve with symfony forms is pretty easy. You are right, you need three separate widgets and three separate validators, there isn't an out of the box solution for this exact situation.
In your form configure method you would have something like:
$this->setWidgets(array(
'date' => new sfWidgetFormDate(),
'time_start' => new sfWidgetFormTime(array('label' => 'Start Time', 'with_seconds' => false)),
'time_finish' => new sfWidgetFormTime(array('label' => 'End Time', 'with_seconds' => false)
));
$this->setValidators(array(
'date' => new sfValidatorDate(), // by default outputs in format Y-m-d
'time_start' => new sfValidatorTime(), // by default outputs in format H:i:s
'time_finish' => new sfValidatorTime(),
));
Let's assume that the object has two properties, as you suggested, both are datetime fields.
In your action you would have something like the following to set the datetime fields:
$values = $this->form->getValues();
$object->setStartDateTime(sprintf('%s %s', $values['date'], $values['time_start']));
$object->setFinishDateTime(sprintf('%s %s', $values['date'], $value['time_finish']));
Edit: another suggestion is not use the built in time widget sfWidgetFormTime as it can look pretty ugly. You can simply use a normal text box (centre aligned, with maxlength=5), and the sfValidatorTime validator will still work perfectly.
Hope that helps.
Your requirement sounds application-specific and not really something the Symfony form framework would help you with out-of-the-box.
I would go with your suggestion of generating start_date and end_date from the output of the three widgets, or if your application needs to return date, start_time and end_time separately later, then possibly just save three values separately and manipulate them when queried.
So, I've done the code for it and it works very well. I've removed all the unnecessary widgets and validators. Here is how I did it:
class VisitForm extends BaseVisitForm
{
private function getMinutes()
{
$minutes = array();
for($i = 0; $i < 60; $i = $i + 5)
{
$minutes[$i] = sprintf('%02d', $i);
}
return $minutes;
}
public function configure()
{
$this->setWidgets(array(
'id' => new sfWidgetFormInputHidden(),
'date' => new sfWidgetFormJQueryDate(array('date_widget' => new sfWidgetFormDate(array('years' => $years, 'can_be_empty'=> false)), 'image' => '/images/icons/calendar.png', 'format'=>'%day%/%month%/%year%')),
'start_time' => new sfWidgetFormTime(array('with_seconds' => false,'can_be_empty'=> false, 'default' => '08:00', 'minutes'=> array_combine($this->getMinutes(), $this->getMinutes()))),
'end_time' => new sfWidgetFormTime(array('with_seconds' => false,'can_be_empty'=> false, 'default' => '08:00', 'minutes'=> array_combine($this->getMinutes(), $this->getMinutes())))
));
$this->setValidators(array(
'start_time' => new sfValidatorTime(),
'end_time' => new sfValidatorTime(),
'date' => new sfValidatorDate(),
));
$this->widgetSchema->setNameFormat('visit[%s]');
$this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
}
protected function doUpdateObject($values)
{
$this->getObject()->setStartDate(sprintf("%s %s", $values['date'], $values['start_time']));
$this->getObject()->setEndDate(sprintf("%s %s", $values['date'], $values['end_time']));
parent::doUpdateObject($values);
}
public function updateDefaultsFromObject()
{
if(!$this->getObject()->isNew())
{
$this->setDefault('date', $this->getObject()->getDateTimeObject('start_date')->format('Y-m-d'));
$this->setDefault('start_time', $this->getObject()->getDateTimeObject('start_date')->format('H:i'));
$this->setDefault('end_time', $this->getObject()->getDateTimeObject('end_date')->format('H:i'));
}
parent::updateDefaultsFromObject();
}
}
I want to create a form for making a reservation for borrowed items. A reservation consists of pick up time, return time and items the reserver wants to borrow and their amounts. For example, I might want to reserve three plates, three knives and three forks for the rest of the week.
In the form, I want to do an AJAX validation that checks whether there is enough items available. Next to each item I have a text box with which the reserver inputs the item amount. After the input, I want to do an onchange call that checks if the amount of items is available for the given dates. Thus, I need to pass the remote function called in the onchange following parameters: item id, item amount (value of the current textfield) and pick up time and return time which are both given in datetime_select fields above. This is my code:
<% with = "'amount='+value+'&item=#{item.id.to_s}&pick_up_time=#{#reservation.pick_up_time.to_s}&return_time=#{#reservation.return_time.to_s}'" %>
<%= text_field_tag "reservation[#{prefix}reserved_items][#{item.id}]", get_amount_value(item, #reservation), :size => 3, :onchange => "#{remote_function(:url => { :controller => :items, :action => :availability }, :with => with, :update => availability_url) }" %>
Obviously, this does not work since #reservation.return_time and #reservation.pick_up_time are not yet set because the form is not yet sent. My question is: how do I get those values? I believe that it should be done via a javascript call, but I didn't manage to insert a javascript call in the "with" variable or at least didn't get it to work. Does anybody have any idea on what I should do?
use prototype selectors $(#reservations_pick_up_time).value
the :with attribute is just a place for you to write JS code that it will display inline