Yii Extension: Quickly Add Dynamic Content Without Writing JS Or Additional Actions! Quickly bind JQuery events and much more… In other words Asteroid gives the ability to lazy load your partials either on load or bound to events like 'click' or 'mouseenter'.
Requirements ¶
- Yii 1.8 or above
- PHP 5.3 or above
Installation ¶
- Place the Asteroid directory in protected/extensions
- In your desired Controller Class add the Asteroid behavior like so:
class MyController extends Controller
{
public function behaviors() {
return array('EAsteroid' =>
array('class'=>'ext.Asteroid.behaviors.EAsteroid')
);
}
…
}
Usage ¶
For purposes of the following examples we will assume we have the below controller and views:
controllers/SampleController.php ¶
class sampleController extends Controller
{
public function behaviors() {
return array('EAsteroid' => array('class' => 'ext.Asteroid.behaviors.EAsteroid'));
}
…
public function actionTestUI()
{
…
$this->render('index');
}
…
}
views/sample/index.php ¶
[html]
<div id="clickMe">Click Here</div>
<div id="myDiv1">
</div>
<div id="myDiv2">
</div>
<div id="myDiv3">
</div>
/views/sample/_p1.php ¶
[html]
<h1><?php echo $var1; ?></h1>
<h2><?php echo $var2; ?></h1>
/views/sample/_p2.php ¶
[html]
<h1><?php echo $var3; ?></h1>
<h2><?php echo $var4; ?></h1>
/views/sample/p3GridView.php ¶
[html]
<?php $this->widget('zii.widgets.grid.CGridView', array(
'id'=>'airport-grid',
'dataProvider'=>$model->search(),
'filter'=>$model,
'columns'=>array(
'id',
'sample_code',
'name',
array(
'class'=>'CButtonColumn',
),
),
)); ?>
Example 1: Using replace() append() And prepend() ¶
Lets say we want to dynamically load the content of the partial view _p1.php into the div "#myDiv1" of test view.
public function actionTestUI()
{
$this->asteroid('a1')
->replace('#myDiv1', '_p1', function(){ return array('var1'=>'Yeah!', 'var2'=>'Thats right!'); })
->orbit();
$this->render('test');
}
Now lets say we have the same scenario but we would also like to append some content to the div "#myDiv2"
public function actionTestUI()
{
$this->asteroid('a1')
->replace('#myDiv1', '_p1', function(){ return array('var1'=>'Yeah!', 'var2'=>'Thats right!'); })
->asteroid('a2')
->append('#myDive2', '_p2', function(){ return array('var3'=>'Im Here!', 'var4'=>'You know it!'); })
->orbit();
$this->render('test');
}
We could also have chosen to prepend
public function actionTestUI()
{
$this->asteroid('a1')
->replace('#myDiv1', '_p1', function(){ return array('var1'=>'Yeah!', 'var2'=>'Thats right!'); })
->asteroid('a2')
->prepend('#myDive2', '_p2', function(){ return array('var3'=>'Im Here!', 'var4'=>'You know it!'); })
->orbit();
$this->render('test');
}
Example 2: Dynamically Rendering An Yii Grid View ¶
When your partial contains a widget like CGridView that registers scripts and or style sheets to POS_HEAD you should use this approach.
public function actionTestUI()
{
$this->asteroid('a1')
->renderMethod('render')
->replace('#myDiv3', '_p3GridView', function() {
$sample = new Sample();
if(isset($_GET['Sample'])) $sample->attributes = $_GET['Sample'];
return array('model' => $sample);
})
->orbit();
$this->render('test');
}
Exmaple 3: Using onEvent() ¶
Lets say we want to replace the content of div "#myDiv1" with the partial _p1.php when I click the div "#clickMe"
public function actionTestUI()
{
$this->Asteroid('a3')->onEvent('click', '#clickMe')
->replace('#myDiv1', '_p1', function() { return array('var1'=>'Yeah!', 'var2'=>'You clicked me…'); })
->orbit();
$this->render('test');
}
Now lets say we want to execute some additional JavaScript on our click event.
public function actionTestUI()
{
$this->Asteroid('a3')->onEvent('click', '#clickMe')
->execJs("alert('I know you would click');")
->replace('#myDiv1', '_p1', function() { return array('var1'=>'Yeah!', 'var2'=>'You clicked me…'); })
->orbit();
$this->render('test');
}
Exmaple 4: Using sendVars() ¶
Lets say we would like to keep track of the number of clicks on a particular DOM element and update the view with the total. Every time a user clicks '#clickMe' we will replace the content of '#myDiv1' with the incremented count.
public function actionTestUI()
{
$this->Asteroid('counterExample')
->onEvent('click', '#clickMe')
->sendVars(function($vars) {
if(empty($vars)) $vars = array('count'=>0);
$vars['count']++;
return $vars;
})
->replace('#myDiv1', '_myPlace3', function($vars) {
return array('var1'=>'Cool I Clicked that', 'var2'=> . $vars['count'] . 'X');
)}
->orbit();
Exmaple 5: Using useBelt() ¶
The 'useBelt' method provides a way to keep things DRY, allowing you to aply groups of Asteroid actions you have defined.
To use 'useBelt' you will need to create at least one instance of EAsteroidBelt. Lets start there and create a folder in 'protected' called 'asteroidBelts' ('webapp/protected/asteroidBelts'). We will use this folder to store our Belts. Now we will create a new class called 'UiHelperAB' and save it to a file called 'UiHelperAB.php' in the 'asteroidBelts' directory we just created. Your class will look something like this:
class UiHelperAB extends EAsteroidBelt
{
public function a1a2($myvar)
{
$this->Asteroid('a1')
->replace('#myDiv1', '_p1', function() use ($myvar) { return array('var1'=>'Yeah!', 'var2'=>$myvar); })
->Asteroid('a2')
->append('#myDive2', '_p2', function() {
return array('var3'=>'Im Here!', 'var4'=>'You know it!');
})
}
public function grid()
{
$this->Asteroid('grid')
->renderMethod('render')
->replace('#myDiv3', '_p3GridView', function() {
$sample = new Sample();
if(isset($_GET['Sample'])) $sample->attributes = $_GET['Sample'];
return array('model' => $sample);
})
}
}
Cool we have an Asteroid Belt, now lets use it in our controller. Lets say we want to use a1a2:
public function actionTestUI()
{
$myvar = "I did this with an Asteroid Belt!";
$this->Asteroid('UIHelper')->useBelt(
'application.asteroidBelts.UiHelperAB', 'a1a2', array($myvar)
)
->Asteroid('someID')->...
->orbit();
...
}
Great, but what if we want to use 'a1a2' and 'grid' in our controller action. We could just repeat the above line again and swap out the method name but there is another way. Lets take a look:
public function actionTestUI()
{
$myvar = "I did this with an Asteroid Belt!";
$this->Asteroid('UIHelper')->useBelt(
'application.asteroidBelts.UiHelperAB',
array(
array('a1a2', array($myvar)),
array('grid', array()),
)
)
->Asteroid('someID')->...
->orbit();
...
}
API ¶
Public Methods ¶
Method | Description |
---|---|
Asteroid | Initilizes Asteroid for the $id passed. $id should be unique unless you intend to overwrite an existing Asteroid. Example: Asteroid('block1') . |
onEvent | Sets a custom event listener. Example: onEvent('click', '#someDomID') ; The default is 'load', 'body'. |
renderMethod | Sets the Yii render type for your Asteroid. renderPartial is the default. Generally you only need to use pass 'render' if you are using Yii widgets like Grid View. |
append | Tells JS to dynamically load the specified view and append it to the specified DOM element. |
prepend | Same as append but prepends to DOM element content. |
replace | Same as append but replaces DOM element content. |
execJS | Call this method to add arbitrary JavaScript. Takes String $js of valid JavaScript. execJS('alert("Yeah!");') |
sendVars | Attach variables to your request. |
useBelt | Attach groups of predefined Asteroid Actions |
orbit | Renders all JS and CSS dependencies. You must Call orbit() as the very last step after all comets have been initialized with |
looks good
In fact, exactly what I've done but in a more durtyer way ...
I will have a look at it.
Works well
Good for displaying "static" widgets, but with GridVIew the search GET request isn't sent when trying to filter the data grid.
RE: Works well: Working with GridView
Hi Luc,
Asteroid should play nicely with GridView if you do the following:
You need to set the renderMethod = 'render' or a custom method that you define in your controller. This is because you need to capture the registered scripts.
You need to capture the $_GET and set the model attributes.
Example (see above):
$this->asteroid('a1') ->renderMethod('render') ->replace('#myDiv3', '_p3GridView', function() { $sample = new Sample(); if(isset($_GET['Sample'])) $sample->attributes = $_GET['Sample']; return array('model' => $sample); }) ->orbit();
Thank you for your help and your nice extension.
I did not set 'id' property of CGridView, so the ajax GET request werent sent
by the gridview filters, however, sort was working well.
Now, with the 'id' set, everything is OKay.
BTW, it works also with bootstrap TbGridview.
I've got plans for using your extension in an application.
Merry Christmas
Demo?
Hello,
It seems to be a nice extension.. Although i couldn't get it to work...
Can you please provide a downloadable demo?
Thanks
@bishoo
Just follow the "usage" tutorial above.
There's only a small typo error:
$this->render('test');
must be replaced with:
$this->render('index');
you can also rename view/sample/index.php to view/sample/test.php and keep $this->render('test') it is as you like !
you can then acces to http://your-Yii-app/sample/testUI
@luc
Thank you luc!
I actually have a probelm when i add this line:
$this->asteroid('a1') ->replace('#myDiv1', '_p1', function(){ return array('var1'=>'Yeah!', 'var2'=>'Thats right!'); }) ->orbit();
it throws "The "dataProvider" property cannot be empty. "
Any clue about that?
@bishoo @luc
First of all thank you Luc for finding that typo (it's now corrected).
Bishoo, Asteroid does not specially reference "dataProvider", however in the grid example (view: p3GridView.php) "dataProvider" is of course used to show the grid. Is it possible you are using this view instead of _p1?
"Call-time pass-by-reference has been removed" Error
First, thank you for this awesome extension! It's exactly what I needed!
Now, when I first installed your extension I got the following error:
PHP Fatal Error: Call-time pass-by-reference has been removed in /Asteroid/behaviors/EAsteroid.php on line 75
The error is caused because since PHP version 5.4 pass-by-references have been removed. So changing this...
call_user_func_array(array(new $belt_class(&$this), $method[0]), $method[1]);
...to this...
call_user_func_array(array(new $belt_class($this), $method[0]), $method[1]);
...solved the problem!
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.