Problems With Widgets

Hi,

I’m working on a page with widgets system and I’m facing two different kinds of problems.

How it should work:

My Page model (wich has widgets through HAS_MANY relation) has a text field called "layout". A typical layout content:


<div id="widget1" class="span6">Widget N°1</div><div id="widget2" class="span6">Widget N°2</div>

This allows me to have a preview of page’s layouts.

My Widget model (belongs_to page) has a text field called "body" and three string field called

  • "title"

  • "widgetId" (like widget1)

  • "type (like simpleWidget)

This is my view:


<?php echo $model->layout; ?>

<?php 

	foreach($model->widgets as $widget){

		$html=$widget->title;

		$widgetId=$widget->widgetId; 

                 // below it drops me the first error

		//$html=$this->widget('application.modules.content.widgets.'.$widget->type,array('widget'=>$widget));

                 // below, for testing purpose, drops me the second error

		//$this->widget('application.modules.content.widgets.'.$widget->type,array('widget'=>$widget));

?>

		<script>document.getElementById("<?php echo $widgetId; ?>").innerHTML="<?php echo $html;?>"</script>

	<?php

	}

?>

As you can see, I want to update my widget1, widget2 … divs with a simple javascript trick. Code above work, each widget title appears in the right div.

But I want to update the divs with the output of the widget like this:


$html=$this->widget('application.modules.content.widgets.'.$widget->type,array('widget'=>$widget));

but it drops me an error:

my simpleWidget.php :


<?php

class SimpleWidget extends CWidget

{

	public $widget;

    public function init()

    {

        parent::init();

    }

	public function run()

		{

		    echo "<h3>test</h3>";

		    //echo "<h3>test ".$widget->title."</h3>";		    

		    //echo $widget->body; 

		}

}

?>

if I uncomment the two last echo, I’ve got the second error:

Any guidance will be much appreciated.

Ok, just found the workaround for the first problem:

in the view:


<?php echo $model->layout; ?>

<?php 

	foreach($model->widgets as $widget){

		$widgetId=$widget->widgetId; 

?>

		<script>document.getElementById("<?php echo $widgetId; ?>").innerHTML="<?php $this->widget('application.modules.content.widgets.'.$widget->type,array('widget'=>$widget));?>"</script>

	<?php

	}

?>

but still my params array(‘widget’=>$widget) are not passed to the widget

Dear luc,

Would you please check wheteher the following is helpful.

The idea here is to return the contents and assigning it to $html rather than rendering it.




<?php 

        foreach($model->widgets as $widget){

                $html=$widget->title;

                $widgetId=$widget->widgetId;

                $html=$this->widget('application.modules.content.widgets.'.$widget->type,array('widget'=>$widget),true);

                 

?>

                <script>document.getElementById("<?php echo $widgetId; ?>").innerHTML="<?php echo $html;?>"</script>

        <?php

        }

?>



Regards.

Hi Seenivasan,

thank you for your advise but I’m sorry to tell you that your solution does not work.

Error while executing application.modules.content.widgets.’.$widget->type,array(‘widget’=>$widget):

I think this is because this code is executed from a view call and in the view context, the obect $widget can’t be passed to the Widget itself …

Can someone confirm this ?

By the way, here is a "half working" solution:

in my view:


<?php echo $model->layout; ?>

<?php 

	foreach($model->widgets as $widget){

		$widgetId=$widget->widgetId; 

	?>

		<script>

		  $('#<?php echo $widgetId; ?>').load("<?php echo $this->createUrl($widget->type,array("widget_id"=>$widget->id));?>");

	</script>

	<?php

	}

?>

below the controller code for $widget->type = simpleList:


	public function actionSimpleList()

	{

		if(isset($_GET['widget_id'])) {

			$id = $_GET['widget_id'];

			$dataProvider=new CActiveDataProvider('Test',array(

			'criteria'=>array(

					//'condition'=>'status=1',

					'order'=>'created_at DESC',

					//'with'=>array('author'),

				),

				'pagination'=>array(

					'pageSize'=>3,

				),

			));

			$this->renderPartial('simpleList',array(

				'dataProvider'=>$dataProvider,

			));

			//echo "<h3>".$model->title."</h3>".$model->body;

		}

	}

And the view for simpleList:


<?php

	$this->widget('bootstrap.widgets.TbListView', array(

		'dataProvider'=>$dataProvider,

		'itemView'=>'_simpleList',

	));

?>

But I’m not fully satisfied with this:

  • It adds database request

  • the TbListView doesn’t load all the javascript stuff (this is understandable because mt trick is to substitute the html content of all my widgets in page)

Dear luc

Thank you for trying my suggestion.

I feel sorry for not being helpful to you.

I hope the following is helpful to you.




<?php

class SimpleWidget extends CWidget

{

    public $widget;

    public function init()

        {

            parent::init();

        }

    public function run()

        {

             echo "<h3>test</h3>";

             echo "<h3>test ".$this->widget->title."</h3>";              

             echo $this->widget->body; 

        }

}

?>




Regards.

I’ve already tested that but always: Undefined variable: widget

A workaround (but a bit tricky):

declare a public $widget; in Page model,

instantiate it in the view (inside the foreach loop): Page::model()->widget=$widget;

then I’m able to call in my simpleWidget: Page::model()->widget->title and so on

Ok, I’ve found an “elegant” way :

This is my view, I’ve do not call any widget or partial anymore




<h2><?php echo $model->title; ?></h2>

<?php echo $model->layout; ?>

<?php 

	foreach($model->pageWidgets as $widget){

		echo '<div id="swapWith_'.$widget->widgetId.'">';

		if($widget->type=="simpleList") {

				$dataProvider=new CActiveDataProvider('Test',array(

					'criteria'=>array(

						//'condition'=>'status=1',

						'order'=>'created_at DESC',

						//'with'=>array('author'),

					),

					'pagination'=>array(

						'pageSize'=>3,

					),

				));

				$this->widget('bootstrap.widgets.TbListView', array(

					'dataProvider'=>$dataProvider,

					'itemView'=>'_simpleList',

				));

		}

		else{

				$this->widget('bootstrap.widgets.TbBox', array(

					'title' => $widget->title,

					'content' => $widget->body,

				));

		}

		echo '</div>';

		?>

		<script>

			$('#<?php echo $widget->widgetId; ?>').html($('#swapWith_<?php echo $widget->widgetId; ?>').html());

			$('#swapWith_<?php echo $widget->widgetId; ?>').hide()

		</script>

		

<?php

	}

?>



I know that doing this buisiness logic in view is bad practice, but it’s the only way I’ve found to register all necessary scripts and css needed by TbListView and other bootstrap goodies …