I've decided to get used to Yii's way of doing things and it's lack of features. However dropdown lists still appear to be my greatest bug-bear with this framework - to the point that due to it's lack of simplicity I'm considering returning to CakePHP.
So can anyone out there possible tell me how one goes about defining a selected option from a dropdown list after someone has posted a form. Currently all my dropdown lists reset to the first value after a post. Here's what I'm doing.
Population is A-OK, but re-population with what was previously selected not so.
You can make your life easier if you put such things into the model. As you require the date to be split up into day/month/year you could do the following:
Add public properties birthDay, birthMonth and birthYear
Add a afterFind() method (called after the record gets populated), split up the date and save it to the according variables ($this->birthDay, …)
Add a beforeSave() method and convert the birthDay, … variables back to a date and store that in $this->date_of_birth
Now you can work with birthDay/Month/Year like with normal model attributes. You can add rules and labels, do massive attribute assignment easily and use them with activeDropDownList.
Nice idea, but for the fact that this would create too much overhead on the database table which already contains over 300k rows. Adding 2 additional integer columns simply to do an age calculation is a little OTT. However, we already have a field for genderId, this is populated but also not being reselected after the post.
The date_of_birth field is essential since through our existing admin we do not want to write a load of CONCAT/BETWEEN statements to create a pseudo date of birth if we want to find members between age groups.
Are dropdown lists really just one part of Yii’s Achilles heel? Please dont think that as me “flaming” Yii, I just find the handling of such a standard form element to be a real chore compared to most other frameworks. Inspite of this I’m still rather keen to use Yii in place of our existing CakePHP stack. My boss is otherwise un-impressed
You got me wrong: I didn't mean to add columns to your Database but to your model file (ActiveRecord class). These public class variables are "virtual": you fill them "afterFind" and read them out "beforeSave" to craeate your real date_of_birth from single values.
About the dropdown lists: I don't have problems with them. Take your time with Yii. If you are more confident with Widgets you'll see, how easy you can create your own date widget, that does exactly what you want.
Thanks for the tip, however perhaps I over-egged the date of birth as being our main bone of contention.
Reselection of any previously selected option on a dropdown list never gets re-selected should a user have form validation errors. Form start up is a doddle we quickly worked out how to define our default selected values if a user hasn't posted the form in the first place. Beyond this we're all stumped!
Other dropdown fields which we can populate without any problems are genderId, stateId and countryId. However when the form gets submitted all these fields first values are selected (though no actually selected since they are obviously the first fields in the option list)
Can you show some code where dropdown lists “forget” their value? This does usually work pretty well. Again: You should make sure, that every dropdown list is related to one single property of your model. This makes life much easier.
With pleasure. We have included the $birthXXX variables as you mentioned to both model and form. We've not added the beforeSave or afterFind methods to the model, as you mentioned since we're only trying to get 1 thing working at a time rather than get all our plates spinning without realising where it's going wrong.
Only few things should help you to get it working:
Add both methods (afterFind/beforeSave), otherwhise your new properties will not be filled from DB/not be stored to DB
Add the properties to safeAttributes()
Remove the lines with $_POST['Member']['date_of_birth']=… and $_POST['Member']['age']= …
Point 2. is essential, as otherwise the attributes will never be saved when you do $member->attributes=$_POST[‘Member’] and thus can never be preselected in your view.
After that you’ll have a pretty clean controller action except for the dropdown value preparation. When you’re ready, wen can try to create a simple widget to also get rid of that
Mike. You are a star. We’ve been wrestling with this for the last 3 days without any success. safeAttributes never said more to us than a verbose method for making posted variables “safe”.
Rather than try and pester you further, by definition of "widget" are you meaning "component"? In CakeLand we would classify them as helpers with a pretty obvious place to drop them. These are items we want to explore rather immediately since each page of our application is made up of repetitive code which is normally mashed-up in the controller before we add more separation to logic.
Pointers would be useful since the docs do help a little, though exactly what class to write/extend and where to place within the application structure would probably end up being a rather hit-or-miss affair.
Once again. Thanks awfully for your help.
I don't know Cake so can't tell about what's the apropriate name for a widget there. In Yii a widget encapsulates parts of a view to be reused in other views.
Your example is ideal to start working with widgets. Try this:
If not present yet, create a folder protected/components and add ‘application.components.*’ to the ‘import’ section of your config.
Put your widget file MyDateSelector.php there. Basic example:
- Create a folder protected/components/views and put a view file myDateSelector.php like this there:
- In your page view replace the dropdowns with this:
Fantastic. You've re-inspired confidence with Yii.
Glad to hear that - now go and spread the word
@Mike: Thank you for helping out.
@wyldie: Regarding the term 'helper', in Yii, a helper is a class mainly consisting of static method. A typical example is CHtml. A helper usually implements functionalities that can be accomplished by a single method call. A widget can be considered as a micro-controller which has its view(s). You can embed widgets in views. A widget is more suitable to deal with UI elements that require complex logic (e.g. a datepicker).