Yii Framework Forum: Looking to extend CForm but how? - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Looking to extend CForm but how? Rate Topic: -----

#1 User is offline   tburandt 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 04-December 11

Posted 03 April 2012 - 10:55 PM

Hello,
I am currently switching over to CForm to display all of my forms (great feature by the way) but because I am using Twitter bootstrap all of my forms are looking a bit out of wack. Let me try to explain a bit more and my thought process.

Here is what is being outputting by CForm...
<div class="row field_Name">
	<label for="Tenant_Name" class="required">Name <span class="required">*</span></label>
	<input name="Tenant[Name]" id="Tenant_Name" type="text" maxlength="50">
</div>


This is kinda what I need CForm to output in order to be compatible with Twitter Bootstrap 2.0...
<div class="control-group">
	<label class="control-label" for="LoginForm_username">Email <span class="required">*</span></label>
	<div class="controls">
		<input name="LoginForm[username]" id="LoginForm_username" type="text">
		<div class="errorMessage" id="LoginForm_username_em_" style="display:none"></div>
	</div>
</div>


So I think I need to create a controller and extend CForm (note: I have already done) then copy/paste in the "render" methods and switch them up to display the correct markup. But here is my problem... currently to render a form I do this, "echo $form->render();" but how do I do this with a component? Note: I have already added the component to my config file and its route is Yii::app()->form. Or am I doing this totally wrong?

Any help would be VERY VERY VERY much appreciated.
0

#2 User is offline   Haensel 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 444
  • Joined: 14-January 11
  • Location:Vienna (Austria)

Posted 04 April 2012 - 03:10 AM

Hi,

First: There is an extension available at http://www.yiiframew...nsion/bootstrap, but I never used it and it may not have any CForm support. If the extension can't be used then it should work that way:

class BootstrapForm extends CForm
{
    public $inputElementClass="BootstrapInputElement";
}

class BootstrapInputElement extends CFormInputElement
{
    public static $coreTypes=array(
        'text'=>'BStextField'
        .....other elements here......
    );

    public $layout="<div>BOOTSTRAP ME<div class="foo">{{label}}</div><div class="bar">{{input}}</div></div>"; //specify how label, hint and input are rendered

    //needs to be overridden to make use of BootstrapHtml instead of CHtml. Also take a look at renderLabel and renderHint for the same reason
    public function renderInput()
    {
    if(isset(self::$coreTypes[$this->type]))
    {
        $method=self::$coreTypes[$this->type];
        if(strpos($method,'List')!==false)
            return BootstrapHtml::$method($this->getParent()->getModel(), $this->name, $this->items, $this->attributes);
        else
            return BootstrapHtml::$method($this->getParent()->getModel(), $this->name, $this->attributes);
    }
    else
    {
        $attributes=$this->attributes;
        $attributes['model']=$this->getParent()->getModel();
        $attributes['attribute']=$this->name;
        ob_start();
        $this->getParent()->getOwner()->widget($this->type, $attributes);
        return ob_get_clean();
    }
    }
}



the placeholders (like {{label}}) will normally be rendered using a CHtml method (CHtml::label, CHtml::textField etc.).
The problems arise when you need a special formatting (like with checkboxlists etc) and the rendered CHtml element just doesn't render like that and can't be configured properly. Then you basically have two options: The not so elegant method is to override the render methods in your new BootstrapInputElement and create some logic the does that for you or you extend CHtml and create a BootstrapHtml class where you create methods for the needed elements like I did above in the renderInput() method. By using the coreTypes array in your new BootstrapInputElement class you actually map the type to the BootsrapHtml method.

class BootstrapHtml extends CHtml
{
    public static function BStextField($name,$value='',$htmlOptions=array())
    {
        return '<div class="foo">'.CHtml::textField(($name,$value='',$htmlOptions=array()).'</div>';
    }
}


So if you specify "text" as element type in your cform config it would create a new BStextField as you mapped it to the BStextField method.

'elements'=>array(
     'username'=>array('type'=>'text', 'maxlength'=>80),
 )


I know it looks really complex, but for the most part it is copy and paste. This might give you an idea

Hope it helps,

Hannes

P.S.: I know that a lot can be done using a view rendering each CForm element via $element->render() and taking care of the formatting in the view itself but as I mentioned: As CHtml is used to create each element you are never in full charge of how the created element itself will look like and the above method has one additional benefit: You can now use BootstrapHtml::BStext to render such an element wherever you want, even if you don't use CForm
0

#3 User is offline   tburandt 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 04-December 11

Posted 04 April 2012 - 01:08 PM

Yeah I need to use CForm because for my project I have about 50 or so forms that need to be created. Some simple and some complicated. Mostly complicated :( but I like how I can clean out my views and keep the form logic elsewhere.


Ok, so here is what I have done...

I made 2 files in my /protected/components/

One file with "class BootstrapForm extends CForm" and the other with "class BootstrapHtml extends CHtml"

I then add those to my config and preload them?


But it get an error...
Missing argument 1 for CForm::__construct(), called in /srv/www/www.powertrade.com/public_html/framework/YiiBase.php on line 219 and defined

0

#4 User is offline   Haensel 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 444
  • Joined: 14-January 11
  • Location:Vienna (Austria)

Posted 04 April 2012 - 04:53 PM

No, you don't need to add them to your config. You just have to tell your new BootstrapForm to use your custom input element class by setting the public property $inputElementClass like:

class BootstrapForm extends CForm
{
    public $inputElementClass="BootstrapInputElement";
}


This tells the form to use the BootsrapInputElement class to render input elements. You have to create that one too like i mentioned above (see the BootstrapInputElement class in my example)
0

#5 User is offline   timster 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 8
  • Joined: 13-July 12

Posted 04 December 2012 - 05:15 PM

Or if you want to be really lazy, you could always render elements bare and include the styling in the css where bootstrap is lacking.

$html=preg_replace('/class=".*?"/', '', $form->render());
$html=preg_replace('/id=".*?"/', '', $html);
echo($html);


:-) Timo
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users