Jquery -Avoid Multiple Insert From Single Submit With Jquery

Hi all, this is my first post on yii. First of, i think this framework is awesome, but right now i am having a problem submitting a form. I’m trying to convert the advance search in admin view to a submit form. So far i have succeeded in submitting the form but it inserts each field in the form on after the other. For e.g i have 3 fields(reference, description & price), when i submit the form…

the first field (reference) is first inserted, then,(reference and description) and then (reference, desc & price) all in different rows. Please, how do i avoid this?

My code…admin.php


Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

$('.search-form').toggle();

return false;

});


$('.search-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

");


Yii::app()->clientScript->registerScript('add', "

$('.addnew-button').click(function(){

$('.add-form').toggle();

return false;

});


$('.add-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

");

?>


<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button btn')); ?>

<div class="search-form" style="display:none">

	<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->

<?php echo " | " .CHtml::link('Add New','#',array('class'=>'addnew-button btn')); ?>

<div class="add-form" style="display:none">

	<?php $this->renderPartial('_form',array(

	'model'=>$model,

)); ?>

</div><!-- add-form -->



_form.php


<?php $form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array(

	'id'=>'product-form',

	'enableAjaxValidation'=>false,

	'action'=>Yii::app()->createUrl('inventory/product/create'),

	'method'=>'post',


)); ?>


<p class="help-block">Fields with <span class="required">*</span> are required.</p>


<?php echo $form->errorSummary($model); ?>


	<?php echo $form->textFieldRow($model,'reference',array('class'=>'span5','maxlength'=>100)); ?>


	<?php echo $form->textAreaRow($model,'description',array('rows'=>6, 'cols'=>50, 'class'=>'span8')); ?>


	<?php echo $form->textFieldRow($model,'price',array('class'=>'span5','maxlength'=>53)); ?>


<div class="form-actions">

	<?php $this->widget('bootstrap.widgets.TbButton', array(

			'buttonType'=>'submit',

			'type'=>'primary',

			'label'=>$model->isNewRecord ? 'Create' : 'Save',

		)); ?>

</div>


<?php $this->endWidget(); ?>



and controller code…


public function actionCreate()

{

$model=new Product;


// Uncomment the following line if AJAX validation is needed

// $this->performAjaxValidation($model);


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

{

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

			$model->coy_id = user()->getModel('coy_id');

			if($model->save())

				user()->setFlash('success',t('cms','You have succesfully added a new product.'));                

$this->redirect(array('quickadmin'));

}


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

'model'=>$model,

));

}



Hi elsopi,

Try "inline" form.




<?php

$form=$this->beginWidget('bootstrap.widgets.TbActiveForm',array(

    'id'=>'product-form',

    'enableAjaxValidation'=>false,

    'action'=>Yii::app()->createUrl('inventory/product/create'),

    'method'=>'post',

    'type'=>'inline', // this is it

));

?>



http://yiibooster.clevertech.biz/components.html#forms

Hi softark,

Thanks for your response. For some reason the code doesn’t work, it doesn’t even insert no more. On submit, it just loads and displays “No result found” like it was a search action. Can you please help me out here. My code remains the same nothing has changed.

Are you using the admin view to do searches and also to add new records? It sounds like there’s still a CGridView on that page.

Can you post the complete code from your ‘admin.php’, please?

This is my admin.php




<?php

$this->pageTitle=t('cms','Product List');

//$this->pageHint=t('cms','Make sure the username, user url and email are unique '); 


$this->menu=array(

array('label'=>'List Product','url'=>array('index'),'linkOptions'=>array('class'=>'button')),

array('label'=>'Create Product','url'=>array('create'), 'linkOptions'=>array('class'=>'button')),

);


/*$this->widget('bootstrap.widgets.TbTabs', array(

	'type'=>'tabs', // 'tabs' or 'pills'

	'tabs'=>array(

			array('id' => 'tab1', 'label' => 'Tab 1', 'content' => $this->renderPartial('_search',array('model'=>$model,), null, true), 'active' => true),

            array('id' => 'tab2', 'label' => 'Tab 2', 'content' => 'loading ....'),

            array('id' => 'tab3', 'label' => 'Tab 3', 'content' => 'loading ....'),

        ),

        'events'=>array('shown'=>'js:loadContent')

));*/




Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

$('.search-form').toggle();

return false;

});


$('.search-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

");


Yii::app()->clientScript->registerScript('add', "

$('.addnew-button').click(function(){

$('.add-form').toggle();

return false;

});


$('.add-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

");

?>


<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button btn')); ?>

<div class="search-form" style="display:none">

	<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->

<?php echo " | " .CHtml::link('Add New','#',array('class'=>'addnew-button btn')); ?>

<div class="add-form" style="display:none">

	<?php $this->renderPartial('_form',array(

	'model'=>$model,

)); ?>

</div><!-- add-form -->

<?php

 if(Yii::app()->user->hasFlash('success')):

 ?>

<div class="notification notesuccess png_bg alert alert-success">

<div>

 <?php echo Yii::app()->user->getFlash('success'); ?>

</div>

</div>

<script type="text/javascript" >

      $(".notification").delay(4100).fadeOut(1300);

</script>

<?php endif; ?>


<?php $this->widget('bootstrap.widgets.TbGridView',array(

'id'=>'product-grid',

	'dataProvider'=>$model->search(array('condition'=>'coy_id='.user()->getModel('coy_id'))),

//'filter'=>$model,

'columns'=>array(

		//'id',

		array(

			'name'=>'reference',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		array(

			'name'=>'description',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		//'price',

		array(

        'header'=>'Price',

        'value'=>function($data){

            return number_format($data->price, 2);

        },

		),

/*		array(

			'header'=>'Units',

			'value'=>'units',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		array(

			'header'=>'Sold',

			'value'=>'sold',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		//'updated_at',

*//*

    MANAGING AN IF STATEMENT BEFORE DISPLAY

		array(

		   'name'=>'price',

		   'value'=>'$data->price=="1" ? "Contact Us for pricing information" : "$".number_format($data->price,0)',

		),

*/

array(

'class'=>'bootstrap.widgets.TbButtonColumn',

),

),

)); ?>



Hi

Thanks.

There’s a lot going on on that page and this makes it a tad difficult to clearly identify the problem. I did notice this piece of code.




....

$('.add-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

....

?>

When your add_new form is submitted, the code above passes it to $.fn.yiiGridView.update which uses the actionAdmin, not the actionCreate. Try removing that code and see if your form works as you expect.

$.fn.yiiGridView.update is designed to work with the search form to populate the gridview with any records that match the criteria in your search form.

One more thing, add a new product using the actual create view (there’s a ‘Create’ link in your admin.php). If it inserts data without any problems, then I would suggest that you move your ‘add_new’ code to a new page or use the create view.

@BikRaven

Hi,

 Thanks for your reply, I had no idea what this  &#036;.fn.yiiGridView.update code did. Anyways, I'm playing around with yii and yiibooster that's why there seem to be a lot going on in that page.

My actual create view works perfectly, what i’m trying to do is bring the form in the admin view and submit it without refreshing the page just as the search action works.

I’m not that good in jquery that’s where my problem is.

This block of code in my admin view works, but refreshes the whole page on submit




<?php

$this->pageTitle=t('cms','Product List');

//$this->pageHint=t('cms','Make sure the username, user url and email are unique '); 


$this->menu=array(

array('label'=>'List Product','url'=>array('index'),'linkOptions'=>array('class'=>'button')),

array('label'=>'Create Product','url'=>array('create'), 'linkOptions'=>array('class'=>'button')),

);


/*$this->widget('bootstrap.widgets.TbTabs', array(

	'type'=>'tabs', // 'tabs' or 'pills'

	'tabs'=>array(

			array('id' => 'tab1', 'label' => 'Tab 1', 'content' => $this->renderPartial('_search',array('model'=>$model,), null, true), 'active' => true),

            array('id' => 'tab2', 'label' => 'Tab 2', 'content' => 'loading ....'),

            array('id' => 'tab3', 'label' => 'Tab 3', 'content' => 'loading ....'),

        ),

        'events'=>array('shown'=>'js:loadContent')

));*/




Yii::app()->clientScript->registerScript('search', "

$('.search-button').click(function(){

$('.search-form').toggle();

return false;

});


$('.addnew-button').click(function(){

$('.add-form').toggle();

return false;

});


$('.search-form form').submit(function(){

$.fn.yiiGridView.update('product-grid', {

data: $(this).serialize()

});

return false;

});

");

?>


<?php echo CHtml::link('Advanced Search','#',array('class'=>'search-button btn')); ?>

<div class="search-form" style="display:none">

	<?php $this->renderPartial('_search',array(

	'model'=>$model,

)); ?>

</div><!-- search-form -->

<?php echo " | " .CHtml::link('Add New','#',array('class'=>'addnew-button btn')); ?>

<div class="add-form" style="display:none">

	<?php $this->renderPartial('_form',array(

	'model'=>$model,

)); ?>

</div><!-- add-form -->

<?php

 if(Yii::app()->user->hasFlash('success')):

 ?>

<div class="notification notesuccess png_bg alert alert-success">

<div>

 <?php echo Yii::app()->user->getFlash('success'); ?>

</div>

</div>

<script type="text/javascript" >

      $(".notification").delay(4100).fadeOut(1300);

</script>

<?php endif; ?>


<?php $this->widget('bootstrap.widgets.TbGridView',array(

 'type' => 'striped bordered',

'id'=>'product-grid',

	'dataProvider'=>$model->search(array('condition'=>'coy_id='.user()->getModel('coy_id'))),

//'filter'=>$model,

'columns'=>array(

		//'id',

		array(

			'name'=>'reference',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		array(

			'name'=>'description',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		//'price',

		array(

        'header'=>'Price',

        'value'=>function($data){

            return number_format($data->price, 2);

        },

		),

/*		array(

			'header'=>'Units',

			'value'=>'units',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		array(

			'header'=>'Sold',

			'value'=>'sold',

			'htmlOptions'=>array('width'=>'200'),

		  ),		

		//'updated_at',

*//*

    MANAGING AN IF STATEMENT BEFORE DISPLAY

		array(

		   'name'=>'price',

		   'value'=>'$data->price=="1" ? "Contact Us for pricing information" : "$".number_format($data->price,0)',

		),

*/

array(

'class'=>'bootstrap.widgets.TbButtonColumn',

),

),

)); ?>



elsopi

As long the form is now submitting, it’s progress :)

In your ‘admin’ view, the model for add_new should be different from the model for search form. Search form is based on the ‘search’ scenario.

In the controller action that renders the admin view add:


$newProduct= new Product;

...//rest of your code

$this->render('admin',array('model'=>$model, 'newProduct'=>$newProduct));



In your admin view

  1. Change the following code so your _form uses your $newProduct model:

<div class="add-form" style="display:none">

        <?php $this->renderPartial('_form',array(

        'model'=>$newProduct,<--this one

)); ?>

  1. Add this as your form submit code

$('.add-new form').submit(function(){

var formUrl = $(this).attr('action'); //gets the form url

var formData = $(this).serialize(); //serialises the form data 

$.ajax({

url: formUrl,

type: 'POST',

data: formData,

success: function(data){

      $('.add-new').html(data);

},

});

return false;//Will stop it from refreshing the whole page on submit.

});

.....

  1. Move the following code from ‘admin’ view to the top of ‘_form’ view.



<?php if(Yii::app()->user->hasFlash('success')): ?>

<div class="notification notesuccess png_bg alert alert-success">

<div>

 <?php echo Yii::app()->user->getFlash('success'); ?>

</div>

</div>

<?php endif; ?>



In your controller

Create an AddNew action using the code below (or adapt your actionCreate if you are not using it elsewhere). If using actionAddnew, remember to change the route in your ‘_form’ view to point to it.


public function actionAddnew()

{

    if(isset($_POST['ajax']) && $_POST['ajax']==='product-form')){

     $model=new Product;

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

      {

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

        $model->coy_id = user()->getModel('coy_id');

        if($model->save())

        {

           user()->setFlash('success',t('cms','You have succesfully added a new product.'));

           

           $model = new Product;

       } 

    }

    $this->renderPartial('_form',array('model'=>$model), false, true);


   }else

    throw new CHttpException('400', 'Invalid request');

}

Not tested. Some good points of reference

CActiveForm documentation

JQuery ajax documentation

JQuery’s serialize function

This tutorial is for juidialog but I found it invaluable for understanding the ajax communication between the controller action and the view.

Thanks

That worked, but not according to how you suggested. Using your "Addnew" actioncontroller, nothing happens, when i check the error console of chrome browser, i see "Failed to load resource: the server responded with a status of 400 (Bad Request) http://localhost/gxcms/project1/backend/inventory/product/create".

…actionAddNew as you suggested


public function actionAddnew()

{

    if(isset($_POST['ajax']) && $_POST['ajax']==='product-form')){

     $model=new Product;

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

      {

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

        $model->coy_id = user()->getModel('coy_id');

        if($model->save())

        {

           user()->setFlash('success',t('cms','You have succesfully added a new product.'));

           

           $model = new Product;

       } 

    }

    $this->renderPartial('_form',array('model'=>$model), false, true);


   }else

    throw new CHttpException('400', 'Invalid request');

}

So i tried the create action with a little tweak…actionCreate


public function actionCreate()

{

	  $model=new Product;

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

      {

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

        $model->coy_id = user()->getModel('coy_id');

        if($model->save())

        {

           user()->setFlash('success',t('cms','You have succesfully added a new product.'));

           

           $model = new Product;

       	} 

       }

    $this->renderPartial('_form',array('model'=>$model), false, true);

}



and it worked…

I also noticed after submitting the form, the grid wasn’t refreshing so i did this, may be it could have been done another way but this was what i came up with.


$('.add-form form').submit(function(){

var formUrl = $(this).attr('action'); //gets the form url

var formData = $(this).serialize(); //serialises the form data 

$.ajax({

url: formUrl,

type: 'POST',

data: formData,

success: function(data){

      $('.add-form').html(data);

	  $('#product-grid').yiiGridView.update('product-grid');// to refresh the grid

},

});

return false;//Will stop it from refreshing the whole page on submit.

});



Now the only problem is if i try adding a new item the second time, the form submits and redirects to …inventory/product/create displaying only _form view.

Thanks for your assistance, I appreciate.

The code I gave you to place in your controller is supposed to be used for ajax requests only. That’s why I set it to render only the ‘_form’ view.

In my earlier post, I wrote that if you are using the addnew action, you should change the route in your form so that it knows to send the data to the addnew action. It seems you didn’t do this so it was sending the form data to the create action.

Follow the instructions just like I provided earlier and, in your ‘_form.php’, change form’s ‘action’ from


 'action'=>Yii::app()->createUrl('inventory/product/create'), 

to


'action'=>Yii::app()->createUrl('inventory/product/addnew'),

and test it again.

Where are you placing the $(’.add-form form’).submit code? It should be in the ‘admin’ view.

Yes, I changed the route in my form when i got the error and copied everything to create action, same error.

I placed this $(’.add-form form’).submit code in my admin view like this


Yii::app()->clientScript->registerScript('add', "


$('.addnew-button').click(function(){

$('.add-form').toggle();

return false;

});


$('.add-form form').submit(function(){

var formUrl = $(this).attr('action'); //gets the form url

var formData = $(this).serialize(); //serialises the form data 

$.ajax({

url: formUrl,

type: 'POST',

data: formData,

success: function(data){

      $('.add-form').html(data);

	  $('#product-grid').yiiGridView.update('product-grid');

	  $('.add-form').reset();

},

});

return false;//Will stop it from refreshing the whole page on submit.

});

");



Now i’m thinking may be i shouldn’t do it that way. :(

I just realised a mistake I made.

In the controller addnew function change this line, if you wish.


 if(isset($_POST['ajax']) && $_POST['ajax']==='product-form')){

to


 if(Yii::app()->request->isAjaxRequest){

It was my fault. In the ajax request, I didn’t send the ajax variable or the form Id which is ‘product-form’. Sorry.

Ok…thanks, but i still have one more problem. If the form is submitted more than once it throws the 400 Invalid Request exception. Why does that happen?

I’m not sure why you are getting the 400 error…

Can you remove the line $(’.add-form’).reset() and see what happens? The reset() clears a form and ‘.add-form’ is a div. You don’t need to reset the form. In the controller action, the model gets re-initialised after the data has been saved.

I’m surprised that you say the $.fn.yiiGridView.update(‘product-grid’) isn’t working for you.


$('.add-form form').submit(function(){

var formUrl = $(this).attr('action'); //gets the form url

var formData = $(this).serialize(); //serialises the form data 

$.ajax({

url: formUrl,

type: 'POST',

data: formData,

success: function(data){

      $('.add-form').html(data);

          $('#product-grid').yiiGridView.update('product-grid');

          $('.add-form').reset(); <--REMOVE THIS

},

});

return false;//Will stop it from refreshing the whole page on submit.

});

That code works for me the cgrid refreshes.

I have removed this line $(’.add-form’).reset() and I still get same error.

Thanks a lot for your assistance, I really appreciate it. I’ll see if i can figure it out.

Thank you…