Jump to content
Larry Ullman's Book Forums

talofo

Members
  • Posts

    5
  • Joined

  • Last visited

talofo's Achievements

Newbie

Newbie (1/14)

0

Reputation

  1. If you wish to use rules(), for validating a form that has fields for more then one model and, one of those models (the n on a 1-N relation), needs to be inserted more then once, you have not the possibility to do it with Yii, unless, you get "hacky". It seems Yii doesn't call the javascript responsible for the N models each time they are rendered, no matter if you do it trough ajax or without it. A component (extended) to activate the errors was necessary and a trickery on performAjaxValidation method was also necessary to make this work. Otherwise, no dice. If someone actually comes to a similar issue, I'm totally ok for providing the code. I just don't paste it here, because it's a lot of code that will pollute more that it helps now.
  2. Not matter what we do, we can't get the validation messages to appear inside those ajax loaded render partials views: When we submit or if we tab navigate the form fields, the _form does display the messages while the _member don't show nothing. I will try to resume the relevant code here: TEAM Controller public function actionMember($index){ $model = new TeamMember(); if (Yii::app()->request->isAjaxRequest) { $this->renderPartial('_member',array( 'model'=> $model, 'index'=> $index )); } } MEMBER Model return array( array('team_id, name, birthdate, email, phone', 'required'), _member partial <div class="row-member<?php echo $index; ?>"> <h3>Member <?php if ($index+1==1){echo $index+1 . '(captain)';} else echo $index+1; ?></h3> <?php echo CHtml::activeLabel($model, "[$index]name",array('class'=>'member')); ?> <?php echo CHtml::activeTextField($model, "[$index]name",array('class'=>'member')); ?> </div> ... _form partial <?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'team-form', 'enableAjaxValidation'=>false, 'enableClientValidation'=>true, 'clientOptions'=>array( 'validateOnSubmit'=>true, ), 'htmlOptions' => array('enctype' => 'multipart/form-data'), )); ?> <fieldset> <section id="members"></section> <?php echo CHtml::button('Add Member', array('class'=>'addMember'));?> </fieldset> <script> $('.addMember').click(function(){ $.ajax({ success: function(html){ $('#members').append(html); }, type: 'get', url: '<?php echo $this->createUrl('member'); ?>', data: {index:$('#members div').size()}, cache: false, dataType: 'html' </script> We have tried with outputProcess set to true, and change renderPartial() to render()... an other trickery stuff... No dice. Any clue ?
  3. Sir Larry, ok... this will be big. Hope you (and others) have the patience and nervers to all of this "newbilities". The good parts (if any) I learned from your Book. (like the relations on models). The bad parts... totally uppon my creation. Let's imagine a form with this structure, where [ ] are buttons on that form: TEAM team name: team address: MEMBERS member name: member phone: [ADD NEW MEMBER] [SUBSCRIBE TEAM] Here are the goals: 1) Validations should happen both, client and server side; (on team and member fields) 2) A flashMessage should appear at the very end. 3) Upon refresh or user miss use, the members fieldset should retain the members information already inserted (if any). This is what I came up with: Model Team: public function relations() { return array( 'teamMembers' => array(self::HAS_MANY, 'TeamMember', 'team_id'), 'country' => array(self::BELONGS_TO, 'Country', 'id'), ); } Model TeamMember: public function relations() { return array( 'team' => array(self::BELONGS_TO, 'Team', 'team_id'), ); } Controller Team: public function actionMember($index) { $model = new TeamMember(); for($i = 0;$i<$index;$i++){ $this->renderPartial('_member',array( 'model'=> $model, 'index'=> $i )); } } public function getExtraModelMember() { $model = new TeamMember; return $model; } public function actionCreate() { $model=new Team; $member=$this->getExtraModelMember(); if(isset($_POST['Team'])) { $model->attributes=$_POST['Team']; if(isset($_POST['TeamMember']) ? $member = $_POST['TeamMember'] : $member = null); if($model->save()) { foreach($member as $team_member) { $mem = new TeamMember(); $mem->attributes=$team_member; $mem->team_id = $model->id; if($mem->validate()) { $mem->save(); } } //create team(equipa) name: $equipa=somethingThatFormatsStrings()); //Create team user $eq= new User; $eq->username=$equipa; if($eq->validate()) $eq->save(); //send email somethingThatSendsEmail(); Yii::app()->user->setFlash('success', "YOUR REGISTRATION WAS SUBMITED WITH SUCCESS!"); $this->redirect(array('team/create','id'=>$model->id,'#'=>'message')); } } $this->render('create',array( 'model'=>$model,'member'=>$member )); } Now the even more messy/durty/ugly part of all this thing. On my Team View _form.php I have this: <?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'team-form', 'enableAjaxValidation'=>false, 'enableClientValidation'=>true, 'clientOptions'=>array( 'validateOnSubmit'=>true, 'beforeValidate'=>'js:function(){ var i=true; $(".errors").empty(); $("#Team_0_email_em_").hide().empty(); $("#Team_1_email_em_").hide().empty(); $("#Team_2_email_em_").hide().empty(); if($("#Team_name").val()==="") i=false; if($("#Team_city").val()==="") i=false; if($(".row-member0").is(":visible")){ if($("#TeamMember_0_name").val()==="") i=false; if($("#TeamMember_0_email").val()==="") i=false; if($("#TeamMember_0_phone").val()==="")i=false; if($("#TeamMember_0_birthdate").val()==="") i=false; if( !validateEmail($("#TeamMember_0_email").val())) { i=false; } } if($(".row-member1").is(":visible")){ if($("#TeamMember_1_name").val()==="") i=false; if($("#TeamMember_1_email").val()==="") i=false; if($("#TeamMember_1_phone").val()==="") i=false; if($("#TeamMember_1_birthdate").val()==="") i=false; if( !validateEmail($("#TeamMember_0_email").val())) { i=false; } } if($(".row-member2").is(":visible")){ if($("#TeamMember_2_name").val()==="") i=false; if($("#TeamMember_2_email").val()==="") i=false; if($("#TeamMember_2_phone").val()==="") i=false; if($("#TeamMember_2_birthdate").val()==="") i=false; if( !validateEmail($("#TeamMember_2_email").val())) { i=false; } } if(i===false) $(".errors").append("<p>You must enter all required fields.</p>"); return i; }' ), 'htmlOptions' => array('enctype' => 'multipart/form-data'), )); ?> And then this: <div class="row"> <?php echo $form->label($model,'name'); ?> <?php echo $form->textField($model,'name',array('size'=>60,'maxlength'=>255)); ?> <?php echo $form->error($model,'name'); ?> </div> <div class="row"> <?php echo $form->label($model,'city'); ?> <?php echo $form->textField($model,'city',array('size'=>60,'maxlength'=>255)); ?> <?php echo $form->error($model,'city'); ?> </div> <div class="row"> <?php echo $form->label($model,'instituition'); ?> <?php echo $form->textField($model,'instituition',array('size'=>60,'maxlength'=>255)); ?> <?php echo $form->error($model,'instituition'); ?> </div> <div class="row"> <?php echo $form->label($model,'country_id'); ?> <?php echo $form->dropDownList($model,'country_id',Country::items(),array('empty'=>'--Select a country--')); ?> <?php echo $form->error($model,'country_id'); ?> </div> I was unable to code a "add more button" to work here, so this is no good: <fieldset> <legend>Members</legend> <label for="numeroMembros">Number of Members <span class="tip">(max 3)</span></label> <select name="membros" id="numeroMembros" onchange="addRemoveFieldsets();"> <option value="1" selected="selected">1</option> <option value="2">2</option> <option value="3" >3</option> </select> <div id="membros"> <?for ($index=0;$index<3;$index++):?> <div class="row-member<?php echo $index; ?>"> <h3>Member <?php if ($index+1==1){echo $index+1 . '(captain)';} else echo $index+1; ?></h3> <div class="row"> <?php echo $form->label($member, "[$index]name",array('class'=>'member')); ?> <?php echo $form->textField($member, "[$index]name",array('class'=>'member member-required')); ?> <?php echo $form->error($model,"[$index]name"); ?> </div> <div class="row"> <?php echo $form->label($member, "[$index]email",array('class'=>'member')); ?> <?php echo $form->textField($member, "[$index]email",array('class'=>'member mail ')); ?> <?php echo $form->error($model,"[$index]email"); ?> </div> <div class="row"> <?php echo $form->label($member, "[$index]phone",array('class'=>'member')); ?> <?php echo $form->textField($member, "[$index]phone",array('class'=>'member member-required')); ?> <?php echo $form->error($model,"[$index]phone"); ?> </div> <div class="row"> <?php echo $form->label($member, "[$index]birthdate",array('class'=>'member')); ?> <?php echo $form->textField($member, "[$index]birthdate",array('class'=>'member birthdate member-required')); ?> <?php echo $form->error($model,"[$index]birthdate"); ?> </div> </div> <?endfor;?> </div> </fieldset> Display the flash messages at the very end on the form: <?php foreach(Yii::app()->user->getFlashes() as $key => $message) { echo '<div class="flash-' . $key . '">' . $message . "</div>\n"; } ?> Finally, this is how I deal with the member validation and behavior: <script> $(document).ready(function() { $('.row-member1').hide(); $('.row-member2').hide(); // $( "#TeamMember_0_birthdate" ).datepicker({ showOn: "button", buttonImage: "/images/calendar.gif", buttonImageOnly: true, dateFormat: 'dd/mm/yy', changeYear: true, yearRange: '1988:1998' }); $( "#TeamMember_1_birthdate" ).datepicker({ showOn: "button", buttonImage: "/images/calendar.gif", buttonImageOnly: true, dateFormat: 'dd/mm/yy', changeYear: true, yearRange: '1988:1998' }); $( "#TeamMember_2_birthdate" ).datepicker({ showOn: "button", buttonImage: "/images/calendar.gif", buttonImageOnly: true, dateFormat: 'dd/mm/yy', changeYear: true, yearRange: '1988:1998' }); }); function validateEmail($email) { var emailReg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/; if( !emailReg.test( $email ) ) { return false; } else { return true; } } $('.mail').each(function(){ $(this).focusout(function(){ if($(this).val()===""){ $(this).next('.errorMessage').hide().empty(); $(this).next('.errorMessage').show().append("<p>This field cannot be blank.</p>"); } else if(validateEmail($(this).val())===false){ $(this).next('.errorMessage').hide().empty(); $(this).next('.errorMessage').show().append("<p>You must enter a valid email.</p>"); } else{ $(this).next('.errorMessage').empty(); } }); }); $('.member-required').each(function(){ $(this).focusout(function(){ if($(this).val()===""){ $(this).next('.errorMessage').hide().empty(); $(this).next('.errorMessage').show().append("<p>This field cannot be blank.</p>"); } else{ $(this).next('.errorMessage').empty(); } }); }); function addRemoveFieldsets(){ var select = $('#numeroMembros'); $('.row-member0').hide(); $('.row-member1').hide(); $('.row-member2').hide(); for (i = 0; i <= select.val()-1; i++) { $('.row-member'+i).show(); } } </script> The bad parts: - That beforeValidate is huge and a pain to debug maintain. - There's not "add more" button. Instead we have a select box. (if the user needs to feel 10 members, he sees 10 field set members at once to fill in!! - The member validation is... unpronounceable... I'm just wondering there why I'm using Yii at all, if I came with such a bad thing. If I'm happy with the model, and the controller is not bad, when I arrive on the views, I get my hair pulled off all the time. By taking all this into consideration what, in our opinion, would be a proper way for dealing with those bad parts ? Hope you still there. Talofo
  4. I thought I've found the solution. I was wrong. I can more or less deal with it, if I use a select field so that the user chooses first, how many members they want to add. If I try to make the "add more" button instead, I need to tell Yii that those new added fields need also to be validated. Scenarios... Need to try and try again - argthh. Cheers.
  5. Hello all, First of all, thanks a trillion for the book. It covers a lot of nice topics. This question is related with a difficulty that I (and perhaps others) may have, regarding a multi model form implementation. Let's say we have a form that should allow a TEAM SUBSCRIPTION and it's members. Obviously, Team is one table, members are another. They do have a relation. Tricky part: This form as a "add new member" button that should visually, display a new member fieldset (render partial?) to be added with more members fields. (And with this, comes a lot of assumptions like): When user hits submit, but a TEAM name already exists (ajax validation), the user informations should be kept. (if they already added two users to that team, those two users should appear again on the form). Without asking for the code, I'm really not getting what should we use on Yii in order to help us out on this scenario. I've read about tabular input, but nothing that explains an overall view using that with Partial Views and Ajax Calls. Can I please have a clue about a possible implementation of this ? This seems to be a very common scenario. You want to subscribe a team of variable members, so you wish to add those members live. Or, you wish to sell a product with some extra optional items, and you wish to allow the user to select has many extra things as they can get. Despite being common, I don't see an overall view regarding such scenarios... If there's a need for a better clarification of the propose, please drop me a reply. Thanks in advance.
×
×
  • Create New...