Whats the best way to dynamically add NEW dhtml content to a form that's generated via Zend_Form. Example, say the form is created like so:
class formUser extends Zend_Form {
public function __construct( $options = null ) {
parent::__construct( $options );
$page1 = new Zend_Form_Element_Text( 'page1' );
$page1->setLabel( 'Page 1' );
$submit = new Zend_Form_Element_Submit( 'submit' );
$this->addElements( array( $page1, $submit ) );
}
}
Here the form creates ONE and only ONE element called "page1," but what if I wanted to throw in an "Add" button in the view that would dynamically generate more elements, like page2, page3, page4, etc, while integrating it with Zend_Form ?
Here is the effect I'm talking about
This isn't me, but he's got the same question and maybe worded it better
In my case, its actually a children and parent relationships. Around this area, a person could have 0 or 15 kids and I wouldn't raise an eyebrow.
Thanks!
I don't have time to go into the details of coding this right now, but here's how I would go about it:
Since you want the structure of your form (and not just it's data) to be editable, you will have to instantiate it and store it in your session.
Instead of just generating some additional HTML markup, you JavaScript would have to make an Ajax call back to your server. The action called this way when the "add" button is clicked, would then alter the Zend_Form instance store in your session. The Ajax call could then return either the additional markup to be inserted or the new version of the entire form markup.
In the former case, it would be up to your JavaScript code to ensure that the markup is inserted in a way that the browser display is consistent with the Zend_Form representation on the server. In the latter case - where the entire form is returned - user input would have to be transferred in the Ajax call or it would be lost when the form is replaced by it's new version.
an implementation of "cg" answer is found well described here.
http://www.jeremykendall.net/2009/01/19/dynamically-adding-elements-to-zend-form/
I don't think you need any special Zend stuff to solve this - the javascript example you posted will add the html in your page where you want it, then when you submit it, you'll have your data on the posted page all the same. Just make sure to follow the naming scheme you use in when you start. You can even use array
$element->setIsArray(true);
to create HTML like this
name="foo[]" id="foo"
An hint to accomplish your task could be to define an hidden input where you could increment your 'pageNb' when you add a new element.
Then to filter & validate your form, you could use a loop to dynamicly create your element and its validations requirement in your controller.
Something like :
// PHP
$userForm = new formUser();
for ($i = 0; $i < $_POST['pageNumber']; ++$i)
{
$element = new Zend_Form_Element_Text('page' . $i);
$element->addValidator('SomeValidator');
$userForm->addElement($element);
}
if ($userForm->isValid($_POST])
{
// bla bla bla
}
// Javascript
function addNewInput ()
{
pageNb = document.getElementbyId('pageNb').value;
pageNb.value = ++pageNb;
// here put the trick to create a new node/input element.
newElement.id = pageNb.value;
}
Related
Ok so here's my situation: I have a page with 5 jquery-ui tabs, 3 of them contain a table each that is generated by php for the data, with each of them there's a set of input to filter according to the date, each table have their own form and update button. Now what I want to achieve is once I refresh and get back to the controller I want to add the corresponding fragment according to the button I pressed.
For example: If I click on the update button from the first tab I want to add #tabs-1, if it's the second one then I want to add #tabs-2.
Now I know I can do:
$_SERVER['SCRIPT_URI'] = $_SERVER['SCRIPT_URI'] . "#tabs-2";
Fine that gives me the correct url, but how do I make the browser go there at runtime? Is there any way to do this?
Here's a part of my controller, the main one.
class PageOptimisationV2C {
public static function main() {
$class = __CLASS__;
$c = new $class;
$c->get();
}
public function get() {
$this->display();
}
private function display() {
$tpl = new PageOptimisationV2V();
$client = ConsulterClient::getClientByNoClient(isset($_GET['cid']) ? $_GET['cid'] : 0);
$tpl->client = $client;
if(isset($_GET['cid'])){
$tpl->StatsLignesCellulaire = self::buildCellStatsReport();
}
$_SERVER['SCRIPT_URI'] = $_SERVER['SCRIPT_URI'] . "#tabs-2";
$tpl->display();
}
}
And then it goes on and displays the page. What would be the optimal solution to get to a fragment of the page, according to the submit button that is pressed.
I tried to make a jsFiddle to show you how the page looked but it got too messy and couldn't get the CSS to work right.
Every detail of information is appreciated.
The only way i'm aware of to do this with PHP is to do a redirect.
header('Location: ' . $_SERVER['REQUEST_URI'] .'#tabs-2');
This of course will result in another request and require you to do some workaround with your flow but its the only way to send a new url back to the browser.
Though it isn't a runtime PHP method you can also just embed the selection Javascript, for example:
var index = $.index($(<?PHP echo $tab; ?>));
$('#tabs ul').tabs('select', index);
and allow it to go through the normal selection process.
You can also just embed a hidden element, something like
<input type="hidden" name="tab-selected" id="tab-selected" value="tabs-2" />
and have some Javascript to check if the element exists and has a value and then select the tab like this:
$(function() {
if ($('#tab-selected').val()) {
var index = $.index($('#tab-selected').val()));
$('#tabs ul').tabs('select', index);
}
});
Today, with a fresh mind, I thought of something else to do while reading MWJump's answer... Why not use the action attribute of the form! It's there for a reason! So for each of my form (I have one in each of my tabs) I slapped the action attribute to be the fragment of the according tab so for the first tab action="#tabs-1" and the second action="#tabs2" and so on...
I found this solution to be the simplest and easiest in this particular case.
I am trying to export cgridview data (current search results) to a CSV by using the excelview extension, by clicking a button.
However, I am not getting the filtered data in my CSV; instead, I'm getting all the records in the model.
This is my controller action I am calling:
public function actionExcel()
{
$model = new PackagingMetric('search');
$this->widget('application.extensions.EExcelView', array(
'dataProvider'=> $model->search(),
'grid_mode'=>'export',
'exportType'=>'Excel5',
'filename'=>'report',
));
}
Would anyone know how to resolve this issue, or where my error is ?
You don't have any search criteria there. Usually you do it like this:
$model = new PackagingMetric('search');
$model->attributes = $_POST['PackagingMetric']; // this would be the model associated with the search form
$model->search();
I don't see anything in your code that takes values from user input, so you should use your search form somehow. Of course, you could have default values in your model, but I don't think that's the case.
Edit:
I looked a bit more into the source code of the extension you are using. It seems that the export buttons are actually standard <a href=''></a> links that send you to a page that's supposed to output the Excel sheet. However, because the actual filter data is not transmitted to that page, there's no way to apply those filters server-side.
Since this is the intended behavior of the extension, there's no elegant way to solve it, but there are messy ways.
A first option would be to tweak the extension yourself, but this will break compatibility with future versions. Another way is to use Javascript to send your data where you need it. In the view file where you are displaying the gridview, you should wrap the widget in a form element or in an ActiveForm with all validation disabled. Then you need to place the following piece of Javascript code somewhere on the page:
var $excelForm = $( '#your_form_id' );
$( '.summary a', $excelForm ).click( function() {
$excelForm.attr( 'action', this.href ).submit();
return false;
});
This will submit the form to the address specified by the export link. Because the form wraps the widget, it will contain the input elements that filter your results, so you will have access to the user-entered filters on the server. You can use the code I originally posted to pick up the data from there.
Note: I am using the default class name for the div that contains the export buttons, which is .summary. If you are using a different class, you should change the respective JS code.
I am using Agile Toolkit. I have a drop-down field in my CRUD.
How can I make the "New" button display different set of values in this drop-down to when the "Edit" button is clicked?
Here is my code:
class page_things extends Page {
function init(){
parent::init();
$p = $this;
$f = $p->add('Form');
$idCat = ($f->get('idCat')?$f->get('idCat'):$this->api->getConfig('idCat','MASP2U03'));
$dpUE = $f->addField('dropdown', 'Category');
$dpUE->setModel('Category');
$dpUE->js('change',$f->js()->submit());
$dpUE->set($idCat);
$f->addSubmit('OK');
$c = $f->add('CRUD');
$c->setModel('things',array('name', 'field1', 'field2', 'field3'))->setMasterField('idCat',$idCat);
if($f->isSubmitted()){
$c->js(true)->show()->execute()->reload()->execute();
}
}
}
Thank you for help !!
use
$crud=$this->add('CRUD',array('allow_add'=>false));
to disable default Add button, then add your own button:
if($crud->grid)$crud->grid->addButton('Add')->js('click')
->frameURL('Add',$this->api->url('./new'));
After this you'll need to create a new page
class page_things_new extends Page {
and inside this page define the form the way you want it to appear no the "add" click. I don't fully understand your question, but with these instruction you can have a different page appear when adding new entries to your crud.
Here's an alternative to Romans that I've tried. It uses $this->api->memorize to store a GET variable chosen in the drop down list in a session variable. Then in the Form, you can set default the chosen value by using recall in the model.
Something like this
in page/things
// load the javascript function (see later)
$this->js()->_load('your_univ');
/*****************************************************************/
/* Code to populate drop down lists - amend where as required*/
$catList=$this->api->db->dsql()->table('category c')
->field('c.id')
->field('c.name')
->where('c.type',$cat_type)
->order('c.id')
->do_getAssoc();
// Check if one is set on URL or default from config and memorize the value
if ($_GET['cat']){
$cat=$_GET['cat'];
} else {
$cat=$this->api-getConfig('idCat');
}
$this->api->memorize('category',$cat);
$f=$p->add('Form',null,null,array('form_empty'))
->setFormClass('horizontal bottom-padded');
$l1=$f->addField('dropdown','category')->setValueList($catList)->set($cat);
// calls a bit of javascript described later to reload with the parameter
$l1->js('change')->univ()->yourfunc($p->api->getDestinationURL(null), $l1);
.. rest of your page code goes here ..
Then in /lib/Model/Category.php
Add the following recall for the field
$this->addField('idCat')->system(true)->visible(false)
->defaultValue($this->api->recall('category'));
Note the system(true) and visible(False) means it wont show up and wont be changeable on the CRUD but you can play around with the options so it shows in the CRUD grid but not in the form.
Finally, the little bit of javascript to make the reload work (Romans might advise a better way to do this). Make sure yourfunc matches in the page and in the js.
in /templates/js/your_univ.js add the following
$.each({
yourfunc: function(url, name){
document.location.href=url+'&cat='+$(name).val();
},
},$.univ._import);
I've got code similar to this working in my own pages. You can probably make it work as a POST as well as the drop down is a form if you dont want the cat to show on the URL.
I'm trying to create 1 base form in Zend which is a part of many other forms.
Eg: the following 3 elements could be a sub form or a mini form that is a part of a larger form :
-Name
-Age
-Address
I just want to re-use the same form in different places - at times adding elements like 'shipping address' etc
I'm getting stuck at the data submission point - when i use multiple forms, i cannot have multiple submit buttons - just one. So obviously all the data is not getting captured - just the data of the form which does contain the sub-form.
Any thoughts here? I have used Zend_Form in the past - but never like this.
You should build up a single Zend_Form object. If you wan to append your Name, Age, and Address to a form and have them look normal, do this:
$display_form = new DisplayForm();
$naa_form = new NameAgeAddressForm();
$display_form->addElements( $naa_form->getElements() );
If you'd like them to look like a sub-form (i.e. kinda grouped together in a sub unit), do this:
$display_form = new DisplayForm();
$display_form->addSubForm( new NameAgeAddressForm() );
Set up your reusable Name/Age/Address form like so (most likely in the init() method of an extension, so you wouldn't see most of this code in your action.)
$littleForm = new Zend_Form();
$littleForm->addElement(new Zend_Form_Element_Text('name'));
$littleForm->addElement(new Zend_Form_Element_Text('age'));
$littleForm->addElement(new Zend_Form_Element_Text('address'));
$littleForm->addElement(new Zend_Form_Element_Submit('submit'));
Since you don't need any other decorators for the NAA form, you set FormElements as the only decorator and remove the submit button from the NAA form
$littleForm->setDecorators(array('FormElements'));
$littleForm->removeElement('submit');
Set up your display/main form like so, and set the order of the NAA form when you add it as a subForm so it displays above the elements of the main form.
$bigForm = new Zend_Form();
$bigForm->addElement(new Zend_Form_Element_Text('shippingAddress'));
$bigForm->addElement(new Zend_Form_Element_Submit('submit'));
$bigForm->addSubForm($littleForm, 'littleForm', 1);
$this->view->form = $bigForm;
Display the form in the view script
echo $this->form;
That's how you do it using decorators. Personally, I cheat and display my forms through a partial script and only use the decorators to render the input elements. Probably you'd want labels and things too...
Im looking for a way to have a form in cakephp that the user can add and remove form fields before submitting, After having a look around and asking on the cake IRC the answer seems to be to use Jquery but after hours of looking around i cannot work out how to do it.
The one example i have of this in cake i found at - http://www.mail-archive.com/cake-php#googlegroups.com/msg61061.html but after my best efforts i cannot get this code to work correctly ( i think its calling controllers / models that the doesn't list in the example)
I also found a straight jquery example (http://mohdshaiful.wordpress.com/2007/05/31/form-elements-generation-using-jquery/) which does what i would like my form to do but i cannot work out how to use the cakephp form helper with it to get it working correctly and to get the naming correct. (obviously the $form helper is php so i cant generate anything with that after the browser has loaded).
I an new to cake and have never used jQuery and i am absolutely stumped with how to do this so if anyone has a cakephp example they have working or can point me in the right direction of what i need to complete this it would be very much appreciated.
Thanks in advance
I would take the straight jquery route, personally. I suppose you could have PHP generate the code for jquery to insert (that way you could use the form helper), but it adds complexity without gaining anything.
Since the form helper just generates html, take a look at the html you want generated. Suppose you want something to "add another field", that when clicked, will add another field in the html. Your html to be added will be something like:
<input type="text" name="data[User][field][0]" />
Now, to use jquery to insert it, I'd do something like binding the function add_field to the click event on the link.
$(document).ready( function() {
$("#link_id").click( 'add_field' );
var field_count = 1;
} );
function add_field()
{
var f = $("#div_addfield");
f.append( '<input type="text" name="data[User][field][' + field_count + ']" />' );
field_count++;
}
Of course, if a user leaves this page w/o submitting and returns, they lose their progress, but I think this is about the basics of what you're trying to accomplish.
This was my approach to remove elements:
In the view, I had this:
echo $form->input('extrapicture1uploaddeleted', array('value' => 0));
The logic I followed was that value 0 meant, not deleted yet, and value 1 meant deleted, following a boolean logic.
That was a regular input element but with CSS I used the 'display: none' property because I did not want users to see that in the form. Then what I did was that then users clicked the "Delete" button to remove an input element to upload a picture, there was a confirmation message, and when confirming, the value of the input element hidden with CSS would change from 0 to 1:
$("#deleteextrapicture1").click(
function() {
if (confirm('Do you want to delete this picture?')) {
$('#extrapicture1upload').hide();
// This is for an input element that contains a boolean value where 0 means not deleted, and 1 means deleted.
$('#DealExtrapicture1uploaddeleted').attr('value', '1');
}
// This is used so that the link does not attempt to take users to another URL when clicked.
return false;
}
);
In the controller, the condition $this->data['Deal']['extrapicture1uploaddeleted']!='1' means that extra picture 1 has not been deleted (deleting the upload button with JavaScript). $this->data['Deal']['extrapicture1uploaddeleted']=='1' means that the picture was deleted.
I tried to use an input hidden element and change its value with JavaScript the way I explained above, but I was getting a blackhole error from CakePHP Security. Apparently it was not allowing me to change the value of input elements with JavaScript and then submit the form. But when I used regular input elements (not hidden), I could change their values with JavaScript and submit the form without problems. My approach was to use regular input elements and hide them with CSS, since using input hidden elements was throwing the blackhole error when changing their values with JavaScript and then submitting the form.
Hopefully the way I did it could give some light as a possible approach to remove form fields in CakePHP using JavaScript.