Tabular form with TabularInputManager extension

HI!

I am working on a form that will have some dynamic fields. For instance, in one Dropdownlist the user chooses number ‘4’, and it will show 4 textFields, which will feed 4 rows in database (with previous respectives validations).

I was wondering if TabularInputManager (by zaccaria) fills my needs. I haven’t seen it working yet, and I’m trying to, but I can’t.

Specifically my problem is in the line:


<?php foreach($descriptionManager->items as $id=>$description):?>

What is $descriptionManager and its items?

I am recreating exactly this example in my localhost with students and classrooms but not working yet, because this variables are not defined anywhere.

Can anyone help me please?

Thank you!

Hi!

There is an error in the example.

You should use studentManager instead of descriptionManager, I mistook when I copied.

With my extension you can avoid to use a textfield for input 4, you can directly use button for add and remove a row.

If you want to implement something of different, is better to do on your own, but you can give a look at the code of the function manage, it will give you some inspiration.

Thanks zaccaria,

I’ve tried to implement for several hours now and I haven’t managed anything yet (because of my “lack of knowledge”). I’ll try another day. Maybe it’s not exactly what I need, because I don’t want it to store the elements in the DB when the user clicks “add”, but at the end of the wizard form (I am using a 4 page stateful form, so i’d like to store the “students” at the final step).

Thanks anyway!

If you don’t want to save this field in db, my extension is DEFINITIVELY not what you need!!

Save time and energy in implementing somehow…

sigh… you could be the first brave to use my toy… what a sadness… :(

Hi,

I am very pleses by your extension, it works awesome, I had a bit of trouble to understand how it works, but it is fully funcional on the create form…

But I am having a little bit trouble on the update side.

here is my controler, what I am missing? cause I can’t delete a row on the update.

tyvm




public function actionUpdate($id)

	{

		$model=$this->loadModel($id);

		

		$cadEscolaProgramaManager = CadEscolaProgramaManager::load($model);

		


		// Uncomment the following line if AJAX validation is needed

		$this->performAjaxValidation($model);


		if(isset($_POST['CadEscola']))

		{

			$model->attributes=$_POST['CadEscola'];

			$cadEscolaProgramaManager->manage($_POST['CadEscolaPrograma']);			

			

			if (!isset($_POST['noValidate'])) {

				

				$valid = $model->validate();

				$valid = $cadEscolaProgramaManager->validate($model) && $valid;

	

				if($valid) {

					if($model->save()) {

						$cadEscolaProgramaManager->save($model);

						$this->redirect(array('view','id'=>$model->inep));

					}				

					

				}

			}

		}


		$this->render('update',array(

			'model'=>$model,

			'escolaProgramaManager'=>$cadEscolaProgramaManager

		));

	}




Thank you for trying my stuff!!

What do you mean with “it doesn’t delete”?

You click on the delete button and the row anyway doesn’t disappear or it looks like correct but at saving nothing changes on the db?

If you are in the first case, check if the button correctly post the data (you can check if there is $_POST[‘modelName’][‘delete’]), if you are in the second case, control that the function deleteOldItems is working properly.

Good luck!

Hi

I figured out where the problem was, I think you should put in your example besides the "actionCreate" an "actionUpdate" too

For it to work perfect I had to to add to my controler actionUpdate an else statement, the action I sent before was the problem





public function actionUpdate($id)

	{

		$model=$this->loadModel($id);

		

		$cadEscolaProgramaManager = new CadEscolaProgramaManager(); //create tabular object

		


		// Uncomment the following line if AJAX validation is needed

		$this->performAjaxValidation($model,$cadEscolaProgramaManager);


		if(isset($_POST['CadEscola']))

		{

			Yii::log(print_r($_POST, true));

			$model->attributes=$_POST['CadEscola'];

			$cadEscolaProgramaManager->manage($_POST['CadEscolaPrograma']); //manage the POST		

			

			if (!isset($_POST['noValidate'])) {

				

				$valid = $model->validate();

				$valid = $cadEscolaProgramaManager->validate($model) && $valid;

	

				if($valid) {

					if($model->save()) {

						$cadEscolaProgramaManager->save($model);

						$this->redirect(array('view','id'=>$model->inep));

					}				

					

				}

			}

		} else {  //here is what I had to do, if it is not a post fill the tabular object with load

			$cadEscolaProgramaManager = CadEscolaProgramaManager::load($model);			

		}


		$this->render('update',array(

			'model'=>$model,

			'escolaProgramaManager'=>$cadEscolaProgramaManager

		));

	}






NOW it works as expected

This implementation works fine, but has the drowbacks of deleting all related record and recreating ex-novo.

You can make it work even with your previous action, you have to pay attention to the deletion of not-needed records.

There is a function that do it:




    public function deleteOldItems($model, $itemsPk)

    {

        $criteria=new CDbCriteria;

        $criteria->addNotInCondition('id', $itemsPk);

        $criteria->addCondition("class_id= {$model->primaryKey}");

 

        Student::model()->deleteAll($criteria); 

    }




This function is called after saving all neede models, the parameters are the main model and the list of id of record to save.

On some database installation the addNotInCondition does,t work properly, maybe you have to take a look at this.

Anyway, as it works properly, you can simply ignore this detail and continue like that, I am really happy that my extension helped it!!

You can give me a “thumb up” in the extension ;)

my problem was that the row wasn’t disappearing when I clicked delete.

the addNotInCondition works fine (mysql) but it was saying not to delete everything, like, I had 3 records with id 1,2,3 the delete was saying delete from table where PK not in (1,2,3) and FK = FKvar

so it was a problem with manage not removing the row for some reason, am I using the wrong version? or there is only 1 file? maybe we are talking with diff versions.

either way is working now and gratz on the extension, sure will thumb up it

See this, is a form created with this widget.

Here is all js, adding a new row in js is a bit difficoult, but removing not at all. If you want you can simply remove the line with js and all should work fine.

For example you can delete the row like that:




function deleteRow(button)

{

 button.parents('tr').detach();

}




You can attach to the button as:




"onClick"="deletePhoto($(this))"



zaccaria, upfront: I’m pretty new to Yii, so I’m sorry when I talk crap.

I tried your extension and had to fiddle with it for a couple of hours. It seems to work now, but I had to implement it a little bit different and I don’t know if this has something to do with your extension or with the Yii framework in general. the render() function at the end of the create action did not pass the manager variable to the view.

What I did instead is to declare the manager as an instance variable of my class and to access it directly via $this->manager inside the view. This approach isn’t clean, but it works for now. Any ideas why the manager didn’t get passed in the render method? Do I have to announce upfront that I want to pass a specific variable?

Another thing: with my approach the validate function on the manager doesn’t seem to work. I took a look in your source code and it does nothing except iterating over all models inside the array and calling Yii’s validate function.

Unfortunately I cannot include my source code here, because the forum software marks my post as spam.

Welcome to the forum!

If the manager is not passed to the variable you have to include in the render:


        $this->render('create',array(

            'model'=>$model,

            'studentManager'=>$studentManager,

        ));

Now in the view create there is a renderPartial, here too you have to add ‘studentManager’=>$studentManager,

Yes, I had it exactly like this, and also passed my tabular input to the partial form. Still didn’t work, but this works now:


<?php foreach ($this->screenshotManager->items as $id => $screenshot): ?>


<?php $this->renderPartial('_formTemplateScreenshot', array('id' => $id,

'model' => $screenshot, 'form' => $form)); ?>


<?php endforeach; ?>

I’m also banging my head against the wall, because one of the fields in the tabular input is a file and the tabular input manager doesn’t seem to play nicely with this one.

Thanks so far for the help!

File filed will be lost anyway on reload of page, there are no hope of doing differently.

If you want to do something better, you should find some jabascript wizard for multiple file entry, but with standard resources the form type="input" will lose the file on reload, no variants.

Greetings, fan of ZTabularInputManager.

Is now available a tutorial for use javascript repetition combined with tabular input.

Enjoy!

Zaccaria ZTabularInputManager could help me with. I do not understand I’m new and I’m really YII zero …

you could set an example for download

eh tried to run the example you have set but I can not work please Zaccaria or someone who can give me an example

I want ahcer is thus a form of a sale. I need to add items for sale and according to what I read ZTabularInputManager meet my worst viewing requirements could not implement it … eh esatre waiting for your help please … sorry for my bad English

This extension is a quite advanced task, is not east to make it work if you are a Yii zero.

Try explain a bit better what is your problem, what exactly is not working, and I will give you the help I can.

I have two related tables sales and products. a sale has many products.

VentasControler I have a controller, model of product sales.

I have also view sales

eh then followed step by step account as below:

Eh I have created the 1st class in my case StudentManager called ProductoManager that is hosted in the Controllers folder which will contain the same class StudentManager:





<?php


class ProductoManager extends TabularInputManager

{


    protected $class='Producto';


    public function getItems()

    {

        if (is_array($this->_items))

            return ($this->_items);

        else

            return array(

                'n0'=>new Producto(),

            );

    }




    public function deleteOldItems($model, $itemsPk)

    {

        $criteria=new CDbCriteria;

        $criteria->addNotInCondition('idproducto', $itemsPk);

        $criteria->addCondition("idventa= {$model->primaryKey}");


        Producto::model()->deleteAll($criteria);

    }




    public static function load($model)

    {

        $return= new ProductoManager();

        foreach ($model->students as $item)

            $return->_items[$item->primaryKey]=$item;

        return $return;

    }




    public function setUnsafeAttribute($item, $model)

    {

        $item->idventa=$model->primaryKey;


    }




}




then the VentaController which is my main driver so I modified the ActionCreate:





    public function actionCreate()

    {

        $model=new Venta();

        $productoManager=new ProductoManager();


        // Uncomment the following line if AJAX validation is needed

        $this->performAjaxValidation($model);


        if(isset($_POST['Venta']))

        {

            $model->attributes=$_POST['Venta'];

            $productoManager->manage($_POST['Producto']);

            if (!isset($_POST['noValidate']))

            {

                $valid=$model->validate();

                $valid=$productoManager->validate($model) && $valid;


                if($valid)

                {

                    $model->save();

                    $productoManager->save($model);

                    $this->redirect(array('view','id'=>$model->idventa));

                }

            }

        }


        $this->render('create',array(

            'model'=>$model,

            'productoManager'=>$productoManager,

        ));

    }









and _form this in views/venta/_form added this:








<div>

<h2>Productos:</h2>

<table>

<tr>

    <th><?php echo Producto::model()->getAttributeLabel('descripcion')?></th>

    <th><?php echo Producto::model()->getAttributeLabel('precio_con_igv')?></th>

    <th><?php echo CHtml::link('add', '#', array('submit'=>'', 'params'=>array('Producto[command]'=>'add', 'noValidate'=>true)));?></th>

</tr>

<?php foreach($productoManager->items as $id=>$producto):?>


<?php $this->renderPartial('_formProducto', array('id'=>$id, 'model'=>$producto, 'form'=>$form));?>


<?php endforeach;?>

</table>

</div>












then I created a new form in views / sell / _formProducto

_formProducto call it contains the product code for the table





<tr>

    <td>

        <?php echo $form->textArea($model,"[$id]descripcion",array('size'=>50,'maxlength'=>255)); ?>

        <?php echo $form->error($model,"title"); ?>

 

    </td>

 

    <td>

        <?php echo $form->textArea($model,"[$id]precio_con_igv",array('rows'=>6, 'cols'=>50)); ?>

        <?php echo $form->error($model,"description"); ?>

    </td>

 

    <td><?php echo CHtml::link(

        'delete', 

        '#', 

        array(

            'submit'=>'', 

            'params'=>array(

                'Producto[command]'=>'delete', 

                'Producto[idproducto]'=>$id, 

                'noValidate'=>true)

            ));?>

    </td>

</tr>






that’s all the error that I get to run is as follows

PHP Error

Description

Invalid argument supplied for foreach()

Source File

C:\xampp\htdocs\agobeta\protected\views\venta\_form.php(115)





<?php foreach($productoManager->items as $id=>$producto):?>




which are items?

I leave my attributes of the product and sales tables

Producto:

idproducto

descripcion

Venta

idventa

I hope your answers thanks thank you very much

I have the same problem did Zack answered anything???