Yii Framework Forum: ajax+clientScript - Yii Framework Forum

Jump to content

  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • You cannot start a new topic
  • You cannot reply to this topic

ajax+clientScript Definitive solution for all clientScript problem in ajax request Rate Topic: ***** 12 Votes

#1 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 13 July 2010 - 02:56 AM

*
POPULAR

Hi all!!

I'd like to discuss a common problem that many time I found in topics.

The problem happens everytime that we have to refresh a content with clientscript in an ajax request.

The two instriment that the framework actually provide are:
$this->renderPartial('view', $params)
and
$this->renderPartial('view', $params, false, true)


The first don't works, because all clientScript inside the refreshed content will not work, and the latter don't work, because all client script outside the refreshed div will not work.

By the way, calling the latter make so that ajax request start a strange recursion, the first time 2 request will be send instead of 1, the second 4, then 8 - 16 and so on.

The common workaround (and what I have always done too) was to avoid to use clientscript for this widget, and that means avoiding even to use CJuiWidget, because the register script file, css file and the script itself in the clientscript.

The workaround concept itself is not bad: the main point is that if we have to render a subview, this subview should be complete and contain all the necessary script for work on his own.

Starting from this idea I implemented this patch for the bug: Attached File  ZController.php (987bytes)
Number of downloads: 813

This file extends CController (so you can put in components and edit /components/Contoller.php for extend it).

This extended class provide a method "renderPartialWithHisOwnClientScript", that will render the clientScript of the subView (and ONLY the clientScript of the subView) at the bottom of the subview itself.

It allows you to work normally, without workaround and without hand-creating CJuiWidget, just remember to call this new renderparital and in the normal renderPartial and in the ajaxRequest function.

NOTE: there is still a problem with id, the components with clientScript inside the content to ajax-refresh should still have a unique id in order to not confilct with external components with the same id.

This cannot be fixed with an extension because CHtml::ID_PREFIX is a const and cannot (for now) be edited.

For YiiDevelopers: this file is a small edit in CControler and CClientScript, please check if it break something and include it in the official release. Let's have a talk about how to fix even the id-conflict problem.

I feel that this detail is the last one Yii's week point in client side managment, let's fix it!
5

#2 User is offline   koz 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 35
  • Joined: 23-June 10

Posted 13 July 2010 - 05:01 AM

Will this work with ajaxlink and ajaxbutton??
0

#3 User is offline   samdark 

  • Having fun
  • Yii
  • Group: Yii Dev Team
  • Posts: 3,350
  • Joined: 17-January 09
  • Location:Russia

Posted 13 July 2010 - 05:38 AM

So scripts will be inserted, parsed and reloaded every ajax request?
Yii 1.1 Application Development Cookbook

Enjoying Yii? Star us at github: 1.1 and 2.0.
0

#4 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 13 July 2010 - 05:42 AM

@koz

It works with ajax-everithing and submit-ddl and whatever. Just pay attention to give a unique id to the components to refresh in order do avoid confision with component outside.

@samdark
Yes, at every ajax request it regenerate all the scripts.

This is necessary for adding components in ajax request.

Is nothing of special, just few line of code. I guess that you can do much better than me!
0

#5 User is offline   koz 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 35
  • Joined: 23-June 10

Posted 13 July 2010 - 05:51 AM

zaccaria i can't put this working... on my FileController.php i got your code:
class ZController extends CController
{
	
	public function renderPartialWithHisOwnClientScript($view,$data=null, $return=false)
	{
		
		$mainClientScript=Yii::app()->clientScript;
		Yii::app()->setComponent('clientScript', new ZClientScript);
		$output=$this->renderPartial($view, $data,  true);
		$output.=Yii::app()->clientScript->renderOnRequest();
		Yii::app()->setComponent('clientScript', $mainClientScript);

		if ($return)
			return $output;
		else
			echo $output;
	}

}
class ZClientScript extends CClientScript
{
	/**
	 * Inserts the scripts at the beginning of the body section.
	 * @param string the output to be inserted with scripts.
	 */
	public function renderOnRequest()
	{
		$html='';
		foreach($this->scriptFiles as $scriptFiles)
		{
			foreach($scriptFiles as $scriptFile)
				$html.=CHtml::scriptFile($scriptFile)."\n";
		}
		foreach($this->scripts as $script)
			$html.=CHtml::script(implode("\n",$script))."\n";

		if($html!=='')
			return $html;
	}

}


then i got

class FileController extends Controller
and on my actionUpdate i got:
		$dataProvider=new CActiveDataProvider('File');
		$this->renderPartialWithHisOwnClientScriptw('index',array(
			'dataProvider'=>$dataProvider,
			'id_project'=>$id_project,
		),false,true);


and it dont work What i got to do? thanks for your help
0

#6 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 13 July 2010 - 05:55 AM

You miss a step in extension.

Put my code in a file named ZController (so components/ZController.php).

Then in file components/Controller.php write:

class Controller extends ZController
{


Like that should work.

P.S: no 'false, true' is needed now, those parameters will be ignored
0

#7 User is offline   koz 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 35
  • Joined: 23-June 10

Posted 13 July 2010 - 06:23 AM

This don't work on my case, i got a list of items and two ajax links for each item, add link and delete link, when i click add link it show delete link and then when i click delete link it suposed to show add linkt then i click in the seond time it dont do nothing.

Any tip ? thanks
0

#8 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 13 July 2010 - 06:28 AM

Can you post your code?
0

#9 User is offline   koz 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 35
  • Joined: 23-June 10

Posted 13 July 2010 - 07:00 AM

http://www.yiiframew...__1

This is my code but with your render
0

#10 User is offline   Chris83 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 440
  • Joined: 27-February 10
  • Location:Helsinki, Finland

Posted 19 July 2010 - 01:19 PM

I solved this with a "minor" hack, I placed the JavaScript in the content to be replaced with AJAX without using CClientScript. This way the JavaScript will work even on the elements in the AJAX content. Kinda ugly but I couldn't think of a better solution.
Best regards,
Chris

My contribution to the Yii community:
Account | Yiistrap | Auth | Bootstrap | NordCms | Rights | LESS | SEO | Img

Follow me:
Twitter | GitHub | Bitbucket
0

#11 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 20 July 2010 - 01:58 AM

@chris83: my solutions does exactly what you said: it place the javascript needed by the content to be replaced in the content itself (I could find better words than your for explain it!!).

This topic wants to be a proposal for framework developer for include this possibiliy in the core framework.

I would be glad if you want to test my solution and give me some feedback!

Thanks a lot for answering!
1

#12 User is offline   ignis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 27-April 10
  • Location:Lithuania - Vilnius

Posted 25 July 2010 - 03:12 AM

Is this one still not in 1.1.3 version ?

Because I'm trying reorder my items list and everything is ok, but reloading CGridview js not reloading.
0

#13 User is offline   zaccaria 

  • Elite Member
  • PipPipPipPipPip
  • Yii
  • Group: Members
  • Posts: 2,232
  • Joined: 04-October 09
  • Location:Moscow

Posted 26 July 2010 - 01:11 AM

From changelog there are no news about that, and no staff member commented my proposal.

I will be pleased if You will workaround your problem by using my solution, the only weak point is that is necessary to give a unique id to all clientscripted items that will be ajax-replaced.

Let us know if it works!
0

#14 User is offline   ignis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 27-April 10
  • Location:Lithuania - Vilnius

Posted 26 July 2010 - 02:23 AM

Tnx for Your answer,

I'll try Your workaround and give You feedback ;)
0

#15 User is offline   ignis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 27-April 10
  • Location:Lithuania - Vilnius

Posted 26 July 2010 - 03:03 AM

ok, I think I miss something..

My controller extends

class ItAdsFieldsController extends ZController
{....


And in my ajax controller I have:

public function actionPublish()
    {

        $curItem = ItAdsFields::model()->findByAttributes(array('field_id' => CHttpRequest::getParam('id')));

        if($curItem !== null)
        {
            d(CHttpRequest::getParam('id'));
            $curItem->publish = ($curItem->publish == '1') ? '0' : '1';
                    
            $curItem->update();

            unset($curItem);
        }

        $dataProvider=new CActiveDataProvider('ItAdsFields',array(
                'criteria' => array(
                    'order' => 'position ASC',
                ),
            )
        );

        $this->renderPartialWithHisOwnClientScriptw('admin',array(
                'dataProvider'=>$dataProvider,
                //'id_project'=>$id_project,
        ),false,true);


        return ;
    }


Zaccaria: at the end of code You can see client cript generation by Your example.

But for me it don't work. I think I'm something missing.

One more thing, ajax regeneration must be on page change in CGridView, because when you go to the next page, the js script is still old, maden for first page.

Thanks for your answering.
0

#16 User is offline   ignis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 27-April 10
  • Location:Lithuania - Vilnius

Posted 26 July 2010 - 04:32 AM

Well, in this case I just 'll wait for yii fix of this problem. And know I just set AjaxUpdate parameter to false for pager and sorting working not within ajax but with GET property and the page refresh all js.

That's simple workaraound :)

Good luck ;)
0

#17 User is offline   benichou 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 3
  • Joined: 08-October 10

Posted 08 October 2010 - 02:55 PM

If you are using this method, be careful with the id of the actions (buttons) rendered. If you have the following rendered as renderPartial:

echo CHtml::ajaxSubmitButton( Yii::t( 'button', 'Save'), Yii::app()->getRequest()->getUrl(), array( 'update' => '#a uniq id'), array('id' => $btn_id.'save' ) );

You need to add the a uniq id to the button else it's going to take resources from your browser and crash your browser

$btn_id = time();

Yii does not take care of uniqueness in the page in in the partially rendered elements.
0

#18 User is offline   g3ck0 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 96
  • Joined: 03-June 09

Posted 14 October 2010 - 09:10 AM

I haven't looked at your code but I want to put a hint here: I have the same issue right now because I want to use Ajax + dialogs for CRUD operations in my CMS. I used renderPartial(..., false, true) too and stumbled over the problem that the jQuery.js was loaded with each Ajax call!

Where is the problem now? jQuery initializes each time and overwrites the existent version. Here an example: Fancybox extends $.fn so you can call methods via $.fn.fancybox.METHOD. When jQuery is loaded a second time this is not possible any more because $.fn.fancybox is undefined.

My solution was that I filter the data directly after the ajax call but before the success method. See dataFilter callback of $.ajax call.
1

#19 User is offline   psikocrisis 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 38
  • Joined: 15-July 10
  • Location:Madrid / Sardinia

Posted 25 October 2010 - 04:09 AM

View Postg3ck0, on 14 October 2010 - 09:10 AM, said:

I haven't looked at your code but I want to put a hint here: I have the same issue right now because I want to use Ajax + dialogs for CRUD operations in my CMS. I used renderPartial(..., false, true) too and stumbled over the problem that the jQuery.js was loaded with each Ajax call!

Where is the problem now? jQuery initializes each time and overwrites the existent version. Here an example: Fancybox extends $.fn so you can call methods via $.fn.fancybox.METHOD. When jQuery is loaded a second time this is not possible any more because $.fn.fancybox is undefined.

My solution was that I filter the data directly after the ajax call but before the success method. See dataFilter callback of $.ajax call.



g3ck0 is absolutely right. There's a bug in CClientScript.


What does the processOutput parameter is to call the CClientScript->render() method in which there is a call to CClientScript->renderCoreScripts(). Here there is any kind of control over the script that are already loaded into the page. So jquery or any other core script can be loaded twice, and this makes developers go crazy. :)


g3ck0, could you post your code? how have you extended CClientScript? So we can find the best solution among all and then post the problem in the bug tracker.


Thanks!
2

#20 User is offline   galymzhan 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 46
  • Joined: 27-October 10
  • Location:Алматы

Posted 09 November 2010 - 04:25 AM

Hi! zaccaria, could you explain how do you deal with css files? For example CDetailView requires own css files to be included, but it seems like ZController doesn't include them in ajax response. Also suppose we have a page with jquery-ui tabs, where tab content is loaded via ajax and containts DatePicker widget. In this case jquery-ui.js is inlcluded twice: first - on page load for Tabs plugin and second - for DatePicker plugin in ajax response. What should we do with that?
2b || !2b that's the question
0

Share this topic:


  • (3 Pages)
  • +
  • 1
  • 2
  • 3
  • 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