Dynamic added form fields based on 1-to-n relation - What framework alternatives? [closed]

半城伤御伤魂 提交于 2019-12-06 14:44:52

Here is the final solution, form id is #quoteForm. Here you "merge" the settings of the two active forms:

//Add car button
        $("#addCar").on('click', function(){
            $.get('<?php echo Yii::app()->createAbsoluteUrl('quote/addCar'); ?>' + '?index=' + (carCount+1), function(data) {
                var settings = $("#quoteForm").data('settings');
                $("#quoteForm").data('settings', null);
                $("#carlist").append(data);
                var settings_new = $("#quoteForm").data('settings');
                carCount++;

                $.each(settings_new.attributes, function(k, v) {
                    settings.attributes.push(v);
                });
               //set the new settings
               $("#quoteForm").data('settings', settings);
        });

I actually use ActiveForm class which extends from CActiveForm and has this method which adds JS to the client script without running the widget(extracted form CActiveForm->run()):

public function registerJs()
{
    $options=$this->clientOptions;
    if(isset($this->clientOptions['validationUrl']) && is_array($this->clientOptions['validationUrl']))
        $options['validationUrl']=CHtml::normalizeUrl($this->clientOptions['validationUrl']);

    $options['attributes']=array_values($this->attributes);

    if($this->summaryID!==null)
        $options['summaryID']=$this->summaryID;

    if($this->focus!==null)
        $options['focus']=$this->focus;

    if(!empty(CHtml::$errorCss))
        $options['errorCss']=CHtml::$errorCss;

    $options=CJavaScript::encode($options);
    $cs=Yii::app()->clientScript;
    $cs->registerCoreScript('yiiactiveform');
    $id=$this->id;
    $cs->registerScript(__CLASS__.'#'.$id,"jQuery('#$id').yiiactiveform($options);");
}

And here is the controller part. You create a form but only render fields, not using it as a widget:

 $form = new ActiveForm();
 $form->enableAjaxValidation = false;
 $form->enableClientValidation = true;
 $form->id = 'quoteForm';


 $car = new \QuotesHistory();
 $this->renderPartial('car_row', compact('car', 'carMakes', 'index', 'form'), false, true);

Here is a small part of the partial view($index is actually the carCount that is passed in the get request), also this partial has a lot more fields and they all validate and submit correctly:

<div class="field-box">
            <?php
                echo $form->hiddenField($car, "[$index]id");
                echo $form->label($car, "[$index]automake_id", array('class'=>'form-label'));

                echo $form->dropDownRow($car, "[$index]automake_id", CHtml::listData($carMakes, 'id', 'name'), array(
                    'data-target' => CHtml::activeId($car, "[$index]automodel_id"),
                    'empty'=>'Select Make',
                ));

                echo $form->error($car, "[$index]automake_id", array(
                    'class'=>'alert-msg',
                    'style'=>'margin: 0;'
                ));
        ?>
    </div>

And on the last partial you need to add this in the end of the view so that the JS is registered.:

<?php
if(Yii::app()->request->isAjaxRequest)  //we dont need this in normal render  
    $form->registerJs();
?>

One final step: In order all this to works you should not double include any JS libs in the ajax response. You can do this in jQuery - http://www.eirikhoem.net/blog/2011/08/29/yii-framework-preventing-duplicate-jscss-includes-for-ajax-requests/

I've tested this code now and it works. If I remove elements I have no problem submitting the form.

Unless I'm misunderstanding your question, I would guess this could be done with any framework:

// Make an ajax (using jQuery or whatever you want to use) call using your new member info (and team id so the member knows what team they belong to
// (JavaScript)
var data = {
  'name' : 'John Doe',
  'age' : 7,
  'team_id' : 24
}
$.post(data, "/member/add", function(data)
{
   if ( data != true ) {
     // Parse error messages here and display them in your page.
   }
});


// member controller
// (PHP)
public function postAdd()
{
  $member = new Member(Input::all());

  $validator = Validator::make(
    Input::all(),
    $rules, // Validation rules defined wherever you want
  );

  // Validation fails
  if ( $validator->fails() ) {
      $messages = $validator->messages(); // I think this returns an array. Can't remember exactly. If not, conver it to an array of error messages
      return json_encode($messages);
  }

  // Validation passes
  $member->save();

  return true;
}

The above PHP is simple syntax I would use with Laravel, which makes stuff like this stupidly easy. I don't know much about Yii but I can't imagine why it wouldn't let you do such a simple operation. Laravel is really great and super simple to learn. I suggest it to any PHP developer these days.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!