Problem retrieving values from Zend_Form_SubForms - no values returned - zend-form

I have a Zend_Form that has 4 or more subforms.
/**
Code Snippet
**/
$bigForm = new Zend_Form();
$littleForm1 = new Form_LittleForm1();
$littleForm1->setMethod('post');
$littleForm2 = new Form_LittleForm2();
$littleForm2->setMethod('post');
$bigForm->addSubForm($littleForm1,'littleForm1',0);
$bigForm->addSubForm($littleForm2,'littleForm2',0);
On clicking the 'submit' button, I'm trying to print out the values entered into the forms, like so:
/**
Code snippet, currently not validating, just printing
**/
if($this->_request->getPost()){
$formData = array();
foreach($bigForm->getSubForms() as $subForm){
$formData = array_merge($formData, $subForm->getValues());
}
/* Testing */
echo "<pre>";
print_r($formData);
echo "</pre>";
}
The end result is that - all the elements in the form do get printed, but the values entered before posting the form don't get printed.
Any thoughts are appreciated...I have run around circles working on this!
Thanks in advance!

This is what I did -
$bigForm->addElements($littleForm1->getElements());
Then, iterated over the form elements like so:
$displayGroup1 = array();
foreach($bigForm->getElements() as $name=>$value){
array_push($displayGroup1, $name);
}
Then, add a displayGroup to $bigForm:
$bigForm->addDisplayGroup($displayGroup1, 'test',array('legend'=>'Test'));
And repeat for multiple display groups.
I'm sure there is a better way to do it, but I'm currently unable to find one out.
This is currently one way I can think of to retrieve all the form values via $_POST, if a form is made up of one or more subforms.
If any one knows of a better solution, please post it!

A Zend_Form does not automatically retrieve values from the $_POST variable. Use:
$bigform->populate($_POST)
Or alternatively:
$bigform->populate($this->_request->getPost())
Another thing to keep in mind is that if the sub forms contain elements with the same name they will clash. To check this use the option View => Page Source in your browser and look at the HTML that is generated. When you see two <input> elements with the same name attribute, then this is the problem.
The Zend solution for this is to give the sub form elements different names using setElementsBelongTo:
$littleForm1->setElementsBelongTo('littleForm1');
$littleForm2->setElementsBelongTo('littleForm2');
Furthermore you should leave out these calls as they serve no purpose (but you should set them for the $bigForm):
$littleForm->setMethod('post');

Related

Form reset for all fields except one Vue.js

I'm trying to find a way to to exclude one field input in my form that is disabled and contains the value of a users ID number
I would like to know how I can tweak this.$refs.form.reset(); because it works perfectly but it clears EVERYTHING and I wish to contain the ID value and resets the rest of the fields like name surname age income etc
The reason why I the ID is important is that the user gives this in a sign-up step at the start and this form that I am talking about is located somewhere else to complete his profile I don't want to ask the user again to type his ID in again.
If anyone knows how to accomplish this it would be a great help
The reset method of the form simply looks at all the inputs bound to it and resets each one within a loop then empties the error bag, observe:
reset (): void {
this.inputs.forEach(input => input.reset())
this.resetErrorBag()
},
There's no reason you can't do the same, except for when they're disabled:
resetForm() {
this.$refs.form.inputs.forEach(input => {
if (!input.disabled) {
input.reset()
}
})
this.$refs.form.resetErrorBag() // necessary to remove validation errors after the field values are removed
}
Then you can call that function (against your Vue instance, not your VForm) with this.resetForm() and it should work out the way you want.
Disclaimer: Can't test it at the moment. input.disabled may not be readily available and may require further inspection of the input element.

Yii2 Gridview get all selected row for all pagination

I wrapped my gridview with Pjax widget like this
\yii\widgets\Pjax::begin();
gridview
\yii\widgets\Pjax::end();
in order to make the gridview make ajax request when I click on each pagination.
I also use ['class' => 'yii\grid\CheckboxColumn'], in column as well.
and I find that when I'm on first pagination I checked some rows and then go to second page and check some rows but when I go back to first page what I've checked is gone.
My question is how can I keep all checkedrow for all pagination
With current conditions (Pjax, multiple pages, yii\grid\CheckboxColumn) it's impossible because of the way it works.
When you click on the pagination links all GridView html content is replaced by new one that comes from the AJAX response.
So obviously all selected checkboxes on the previous page are gone.
Few possible ways to solve that:
1) Write custom javascript and server side logic.
As one of the options, you can send AJAX request to server with parameter meaning that user has chosen to select all data for the bulk delete operation (or use separate controller action for bulk deletion). In this case actually we don't need to get the selected data from user, because we can simply get them from database (credits - Seng).
2) Increase number of displayed rows per page.
3) Use infinite scroll extension, for example this.
4) Break desired action in several iterations:
select needed rows on first page, do action (for example, delete).
repeat this again for other pages.
You can get selected rows like that:
$('#your-grid-view').yiiGridView('getSelectedRows');
[infinite scroll] : http://kop.github.io/yii2-scroll-pager/ will work good if you do not have any pjax filters. If you have filters also in play, do not use this plugin as it does not support pjax filters with it. For rest of the applications it is perfect to use.
Update1 : it seems to be straight forward than expected, here is the how I accomplished it
Add following lines to the checkbox column
'checkboxOptions' => function($data){
return ['id' => $data->id, 'onClick' => 'selectedRow(this)'];
}
Now add following JS to the common js file you will have in your project of the page where this datagrid resides
var selectedItems=[]; //global variable
/**
* Store the value of the selected row or delete it if it is unselected
*
* #param {checkbox} ele
*/
function selectedRow(ele){
if($(ele).is(':checked')) {
//push the element
if(!selectedItems.includes($(ele).attr('id'))) {
selectedItems.push($(ele).attr('id'));
}
} else {
//pop the element
if(selectedItems.includes($(ele).attr('id'))) {
selectedItems.pop($(ele).attr('id'));
}
}
}
Above function will store the selected row ids in the global variable array
Now add following lines to pjax:end event handler
$(document).on('pjax:end', function () {
//Select the already selected items on the grid view
if(!empty(selectedItems)){
$.each(selectedItems, function (index,value) {
$("#"+value).attr('checked',true);
});
}
});
Hope it helps.
I just solved this problem and it works properly with Pjax.
You may use my CheckboxColumn. I hope this can help. The checked items are recorded with cookies.
You can read the part with //add by hezll to understand how to fix it, because I didn't provide a complete general one.
Hope it works for you.
https://owncloud.xiwangkt.com/index.php/s/dGH3fezC5MGCx4H

Store $_POST in Yii2 session

I'm having a little trouble with my quiz form. I'm using a page to show a single question that a user answers, from there I was hoping to save the question id and option id (My form is multiple choice, i set the options).
My HTML looks like this:
<input type="radio" name="question[3]" value="4">My Answer
When the form is posted I am doing this
if(isset(Yii::$app->session['question'])){
// Get posted array
$question = $_POST['question'];
Yii::$app->session['question'] = $question;
print_r(Yii::$app->session['question']);
}
So it's saved into my session as:
Array
(
[3] => 4
)
Which is fine, the problem I'm finding is trying to save the next question without overwriting the previous [question_id] => [option_id].
I understand why the following code just overwrites the existing the session['question'] variable. But I'm struggling to be able to save each question and answer array to my variable.
I have tried Yii::$app->session['question'][$i] = $question; and get Indirect modification of overloaded element of yii\web\Session has no effect
I've also tried array_push and array_merge to try and combine the previous array of question and chosen option, but have had no luck either. What am I doing wrong here please?
The correct way to do this is
$q = $_POST['question'];
Yii::$app->session['question'] = array_merge(Yii::$app->session['question'], [$question]);
You should do
Yii::$app->session['question'][] = $question;
Notice the extra []

web2py SQLFORM accepting too fast

I have a web2py SQLFORM that gets generated and returned by an AJAX call and the form is put in a DIV I defined.. I want that SQLFORM to be an update form, not an insert form. The problem is the form immediately runs it's accept function once it is written to that DIV. This doesn't happen if the form is for inserting, only updating. That initial accept fails and hitting the submit button does not allow for a second accept.
I don't know why the accept fails or why it happens immediately.
heres the JavaScript function that makes the AJAX call
function displayForm(currID){
//Remove everything from the DIV we want to use
$('#window').empty();
//Call the ajax to bring down the form to update the series
ajax('{{=URL('newForm')}}/'+currID,
[], 'window');
}
And here is the newForm controller
def newSerForm():
record = db.myTable(request.args[0])
form = SQLFORM(db.myTable, record, fields=['series_name','image_thumbnail'])
if form.accepts(request.vars,session):
print 'Series update successful!'
else:
print 'Series update Failed...'
return form
displayForm is fired by clicking a button and once you do the form accepts and fails and the submit button doesn't work again. Is there a way to make an SQLFORM do this? The weird thing is if I change this to make inserts into myTable, it works fine. It behaves exactly as it should. But doing it this way doesn't work.
Ok now this is where it gets weird.
I tried to achieve the same functionality here with a totally different approach, an iFrame. I made new functions in my controllers that create the form based on request.args[0]. looks like this
def editEntry():
print request.args[0]
record = db.myTable(request.args[0])
form = SQLFORM(db.CC_user_submission, record, fields=['series_name', 'image_thumbnail']).process()
return dict(form=form)
And then a corresponding HTML page that just displays form. What could be simpler right? I go to that page based on a link that gives the correct argument. Take me to a page with a form for updating. Updating works perfect. Great, now lets put it in an iFrame instead of linking to it. I put it in an iFrame on the original page. Open up the iFrame. Doesn't work. I have no idea what is going is there any part of an explanation to this?
By using the iFrame method I actually got this one to work. Since it required an iFrame to be appended with jQuery which needs quotes and the iFrame URL which also needs quotes, the notation got pretty confusing but it's doable. Looked like this:
var myURL = "{{=URL('editEntry')}}/"+idArg.toString();
$('#window').append("<iframe src = " + myURL + " width='450' height='400'> </iframe>");
It's not pretty but it works.

Flex 3.5.0; Update ComboBox display list upon dataprovider change

I have two related ComboBoxes ( continents, and countries ). When the continents ComboBox changes I request a XML from a certain URL. When I receive that XML i change the DataProvider for the countries ComboBox, like this:
public function displayCountryArray( items:XMLList ):void
{
this.resellersCountryLoader.alpha = 0;
this.resellersCountry.dataProvider = items;
this.resellersCountry.dispatchEvent( new ListEvent( ListEvent.CHANGE ) );
}
I dispatch the ListEvent.CHANGE because I use it to change another ComboBox so please ignore that (and the 1st line ).
So, my problem is this: I select "ASIA" from the first continents, then the combobox DATA get's updated ( I can see that because the first ITEM is an item with the label '23 countries' ). I click the combo then I can see the countries.
NOW, I select "Africa", the first item is displayed, with the ComboBox being closed, then when I click it, the countries are still the ones from Asia. Anyway, if I click an Item in the list, then the list updates correctly, and also, it has the correct info ( as I said it affects other ComboBoxes ). SO the only problem is that the display list does not get updated.
In this function I tried these approaches
Converting XMLList to XMLCollection and even ArrayCollection
Adding this.resellersCountry.invalidateDisplayList();
Triggering events like DATA_CHANGE and UPDATE_COMPLETE
I know they don't make much sense, but I got a little desperate.
Please note that when I used 3.0.0 SDK this did not happen.
Sorry if I'm stupid, but the flex events are killing me.
Setting the dataprovider of the comboBox' dropdown seems to fix this problem.
this.resellersCountry.dataProvider = items;
this.resellersCountry.dropdown.dataProvider = items;
this.resellersCountry.dropdown.dataProvider = items;
works (Flex SDK 3.5)
Hope this bug fixed in 4.0
In addition to Christophe´s answer:
When you are using data binding in your ComboBox you need to use the BindingUtils to set the dropdown´s dataprovider:
MXML:
<mx:ComboBox id="cb_fontFamily"
width="100%"
dataProvider="{ model.fontFamilies }" />
Script:
private function init():void
{
BindingUtils.bindSetter(updateFontFamilies, model, "fontFamilies");
}
private function updateFontFamilies(fontFamilies:ArrayCollection):void
{
if (cb_fontFamily != null) cb_fontFamily.dropdown.dataProvider = fontFamilies;
}
Thanks to Christophe for pointing in the right direction.
Another workaround, outlined in an Adobe Community forum post, is to avoid re-assigning a different ArrayCollection object to the ComboBox, and instead re-using (and re-populating) the original one instead:
items.removeAll();
for each (var item:* in newItems)
{
items.addItem(item);
}