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

#21 User is offline   g3ck0 

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

Posted 09 November 2010 - 11:26 AM

At the moment I have no working extended version of CClientScript because I'm working on some jQuery Plugins. I think I will work on this problem at the end of this month (november).

I don't think that this will be integrated in the core because most time it will be a special solution for a special problem. To generalize will be very problematic -- but I will try to handle this ;)
0

#22 User is offline   szako 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 17-May 10

Posted 17 December 2010 - 06:41 AM

@zaccaria:

Nice hack you made! Tho I ran into a bug. The core scripts don't get registered ergo it can cause js errors. For example:

CListView::registerClientScript() has this row:

$cs->registerCoreScript('bbq');


It won't get registered because you included only the user scripts in ZClientScript::renderOnRequest().
I'm trying to find a workaround now.

The missing of the above script causes this javascript error:

$.param.querystring is not a function

-------------
m(o_O)m
0

#23 User is offline   szako 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 17-May 10

Posted 17 December 2010 - 05:09 PM

My main problem is, you cannot run ajaxed js code without eval().

I modified CListView's html code, so rows could be updated, deleted and more rows could be added. (used inputs + ajaxbuttons) After each deletion or addition I updated the content of the list. I managed to give each button an unique id this way:

    <?php echo CHtml::ajaxButton('Save',
        array('attributeValue/update', 'id' => $data->id),
        array(
            'success' => "js: function(data, textStatus, XMLHttpRequest) { $.fn.yiiListView.update('list'); }",
            'type' => 'post',
        ),
        array('name' => 'tl'.CHtml::$count)
    ); ?>
    <?php CHtml::$count++; ?>


When I updated the content it didn't interfere with the selectors from the main code.

If you include the main script again in the widget, you could get errors, like I did with loading jquery again. (CListWidget's JS crashed), you have to manually include the files:

Yii::app()->getClientScript()->registerCoreScript('bbq');


I modified zaccaria's code, so the scripts could be placed where they belong and this way js script can be surrounded by onload & ondomready events. (JQuery undefined error!)

	public function renderOnRequest()
	{
		$html='';
		foreach($this->scriptFiles as $scriptFiles)
		{
			foreach($scriptFiles as $scriptFile)
				$html.=CHtml::scriptFile($scriptFile)."\n";
		}

                $scripts=isset($this->scripts[self::POS_END]) ? $this->scripts[self::POS_END] : array();
                foreach($this->scripts as $k=>$script) {
                    if ($k == self::POS_READY) {
                        $scripts[] = "jQuery(function($) {\n".implode("\n",$script)."\n});";
                    }
                    elseif($k == self::POS_LOAD) {
                        $scripts[] ="jQuery(window).load(function() {\n".implode("\n",$script)."\n});";
                    }                     
                }
                if (!empty($scripts)) $html .= CHtml::script(implode("\n",$scripts))."\n";

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


The problem was, that when I updated list content the <script> tags were removed via the jquery functions. You cannot add/modifiy <script> tags via JQuery, only hardcoded style. You have to get it as a string and eval() it.

So, after refresh you would have to "reassign" JQuery delegates, because the ids could have been modified, assigned to other objects:

jQuery('body').delegate('#tl0','click',function(){jQuery.ajax({'success': function(data, textStatus, XMLHttpRequest) { $.fn.yiiListView.update('tulajdonsag-lista'); },'type':'post','url':'/yii-gsmhome/admin/attributeValue/update/id/2','cache':false,'data':jQuery(this).parents("form").serialize()});return false;});
jQuery('body').delegate('#tl1','click',function(){jQuery.ajax({'success': function(data, textStatus, XMLHttpRequest) { $.fn.yiiListView.update('tulajdonsag-lista'); },'type':'post','url':'/yii-gsmhome/admin/attributeValue/delete/id/2','cache':false,'data':jQuery(this).parents("form").serialize()});return false;});


I could try to examine the right <script> tag's content and eval it, so it always becomes updated.

By the way the same kind of thing happens if you have custom buttons in CGridView. When you paginate through ajax, and change page, you have to reassign the events attached to the "new" buttons loaded via ajax. Otherwise it doesnt work.

Any thoughts of this?
-------------
m(o_O)m
0

#24 User is offline   blux 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 15-December 10

Posted 30 December 2010 - 09:28 AM

I ran into a similar problem and tried to solve it with the extended client script. As others have pointed out though, the solution has its drawbacks:

  • CSS files required by some widgets are not included in the AJAX response
  • reloading core scripts will invalidate previously registered $.fn method calls (and render them unusable)

An alternative solution; just perform a renderPartial for the AJAX request, and filter the resulting HTML on the client side. First, register all statically loaded CSS and JS files:

Yii::app()->clientScript->registerScript('register_static_css_js', "                                                                               
$(function() {                                                                                                                                         
     script_files = $('script[src]').map(function() { return $(this).attr('src'); }).get();                                                                                                                                          
     css_files = $('link[href]').map(function() { return $(this).attr('href'); }).get();                                                                                                                                          
});");

Then, in the AJAX success callback, only include external script and stylesheets that are not yet present in the DOM. Inline Javascript is always included.

success: function(data) {                                                                                                                  
    var reply = $(data);                                                                                                                   
    var target = $('#some_element');
    target.html('');                                                                                                                         
    target.append(reply.filter('script[src]').filter(function() { return $.inArray($(this).attr('src'), script_files) === -1; }));           
    target.append(reply.filter('link[href]').filter(function() { return $.inArray($(this).attr('href'), css_files) === -1; }));              
    target.append(reply.filter('#content'));                                                                                                      
    target.append(reply.filter('script:not([src])'));                                                                                        
}


I'm pretty sure the jQuery code can be optimized, still working on that. Any suggestions?
3

#25 User is offline   szako 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 56
  • Joined: 17-May 10

Posted 03 January 2011 - 06:27 PM

Promising solution, dude!
-------------
m(o_O)m
0

#26 User is offline   blux 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 11
  • Joined: 15-December 10

Posted 04 January 2011 - 07:25 AM

View Postszako, on 03 January 2011 - 06:27 PM, said:

Promising solution, dude!


Thanks for the feedback :)

Slight improvement to the success callback to prevent redundant requests in case more than one AJAX request is done:

success: function(data) {                                                                                                                  
    var reply = $(data);                                                                                                               	
    var target = $('#some_element');
    target.html('');                                                                                                                     	
    target.append(reply.filter('script[src]').filter(function() {
        if ($.inArray($(this).attr('src'), script_files) === -1) {
            script_files.push($(this).attr('src'));
            return true;
        }
        return false;
    }));       	
    target.append(reply.filter('link[href]').filter(function() {
        if ($.inArray($(this).attr('href'), css_files) === -1) {
            css_files.push($(this).attr('href'));
            return true;
        }
        return false;
    }));              
    target.append(reply.filter('#content'));                                                                                                      
    target.append(reply.filter('script:not([src])'));                                                                                        
}

3

#27 User is offline   dimilow 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 85
  • Joined: 16-March 09

Posted 04 January 2011 - 07:53 PM

@blux this is nice!
tipstank.com - where I share my coding stuff
0

#28 User is offline   intel352 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 196
  • Joined: 05-February 10
  • Location:Southport, NC

Posted 06 January 2011 - 02:59 PM

Here's a simple solution, intended to help this same situation:
http://code.google.c.../detail?id=1961

Quote

The patch allows me to issue a renderPartial to answer an Ajax request. Prior to the renderPartial, I toggle renderScriptFiles to false, i.e.:

        Yii::app()->getClientScript()->renderScriptFiles = false;
        $this->renderPartial('someView', null, false, true);


This results in a partial view being rendered, with inline JS intact, and the jquery.js file excluded.


Not necessarily a complete solution, but works for me, and may hopefully rope Qiang into the discussion for his input ;-)
Need live Yii support? - Join the #yii IRC channel on Freenode!
0

#29 User is offline   khairil 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 23-December 10
  • Location:Malaysia

Posted 17 January 2011 - 03:16 AM

Thanks a lot Zaccaria. Your solution works like a charm.
0

#30 User is offline   jeremy 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 17-June 09
  • Location:Massachusetts, USA

Posted 27 January 2011 - 08:37 PM

I too am having this extremely frustrating problem. @intel352's patch #1961 works if one is generating the script in the ajax response. BUT if the ajax response uses a zii widget which relies on jQuery, it does not work. I applied the CClientScript patch from #1961, then did:

    Yii::app()->getClientScript()->renderScriptFiles = false; // use #1961
    $this->beginWidget('zii.widgets.jui.CJuiDialog', array(
        'id'=>'HistoryDivPopup',
        'options'=>array(
            'title'=>Yii::t('DR','Change History'),
            'autoOpen'=>true,
            'modal'=>true,
            'width'=>600,
            'position'=>array(300,200),
        ),
    ));
    echo $out; // dialog content
    $this->endWidget('zii.widgets.jui.CJuiDialog');


the CJuiDialog does not auto-open, as it does when jQuery is present.

But without renderScriptFiles = false, then after I close the dialog, ajax elements that were already present in the page no longer work. I get "jQuery.yii is undefined". Specifically, I have a "Cancel" button which was rendered in the original view, like this:
            echo CHtml::resetButton(Yii::t('DR','Cancel'),array('submit'=>$this->createUrl($return)));


can anyone help me with this? I am at the very beginning stage of learning javascript and jQuery.
0

#31 User is offline   intel352 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 196
  • Joined: 05-February 10
  • Location:Southport, NC

Posted 27 January 2011 - 09:18 PM

Hi Jeremy, if the problem is that jQuery is missing, then just make sure jQuery is registered in the view that will be pulling in your Dialog window.

If you need more direct help, contact me at jon [at] phpsitesolutions.com
Need live Yii support? - Join the #yii IRC channel on Freenode!
0

#32 User is offline   jeremy 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 17-June 09
  • Location:Massachusetts, USA

Posted 27 January 2011 - 10:09 PM

jQuery is already present in the main view, because I've used CHtml::SubmitButton() and CHtml::resetButton(). Explicitly registering jquery.js and jquery.yii.js at the top of the _form.php does not help; nor does doing this in my main.php layout.

Maybe I should have mentioned this is all CRUD-generated code (very simple form) using CActiveForm widget.

Also tried @zaccaria's solution, which works, but as others pointed out it also blocks the css for the CJuiWidget.

{EDIT}: <duh> the solution in my case was much simpler. before rendering the widget in my partial view, I do:
Yii::app()->getClientScript()->scriptMap=array('jquery.js'=>false,'jquery.min.js'=>false); // don't resend jquery.cs


{/EDIT}
0

#33 User is offline   jeremy 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 17-June 09
  • Location:Massachusetts, USA

Posted 28 January 2011 - 03:05 PM

I think the answer to my last post is here:
http://www.yiiframew...lientscriptpos/

worked around it by using patch #1961, plus loaded jquery-ui in my main layout. I'm not crazy about this solution, and hoping for an improvement. Maybe patching the widgets per post 12697, and then using scriptMap to exclude jquery.js from loading again ?
0

#34 User is offline   silintzir 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 13
  • Joined: 16-December 10

Posted 04 February 2011 - 06:47 AM

I'm trying to load a CJuiDialog from an external view with the ZController render function but it seems that it doesn't load the requested jquery javascript files and css. How can I do that?? Should I use some specific function inside the view??
0

#35 User is offline   ClaCS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 21-January 11

Posted 16 March 2011 - 07:40 AM

Hi!

I can't extend 'components/Contoller.php' to ZController because I'm using the new version of 'Rights' module and the components/Contoller.php' extends to RController :(

I can't find solution for this problem :unsure:
0

#36 User is offline   jeremy 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 57
  • Joined: 17-June 09
  • Location:Massachusetts, USA

Posted 20 March 2011 - 10:08 AM

The solution is to cascade the inheritance, so ZController extends RController, which extends CController; or the other way around if it seems better. I am not familiar with the Rights module so I don't know which order the extension will work best.

View PostClaCS, on 16 March 2011 - 07:40 AM, said:

Hi!

I can't extend 'components/Contoller.php' to ZController because I'm using the new version of 'Rights' module and the components/Contoller.php' extends to RController :(

I can't find solution for this problem :unsure:

0

#37 User is offline   Bambukas 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 5
  • Joined: 13-January 11
  • Location:Lithuania

Posted 24 March 2011 - 01:30 AM

Hi, everyone i'm trying to create ajax call but fail and fail. So does enyone can help me. Can you write simple code how to call action from controller with ajax on mouse over or on mouse move? :)
0

#38 User is offline   ClaCS 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 21-January 11

  Posted 12 April 2011 - 08:32 AM

View Postjeremy, on 20 March 2011 - 10:08 AM, said:

The solution is to cascade the inheritance, so ZController extends RController, which extends CController; or the other way around if it seems better. I am not familiar with the Rights module so I don't know which order the extension will work best.


Hi!

the cascade inheritance is works! but the ajax+clientScript problem is still :(
0

#39 User is offline   sgomez84 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 4
  • Joined: 13-February 11

Posted 14 April 2011 - 08:36 AM

Hey zaccaria,

Thanks so much for this solutions. With my implementation, the CJuiDialog worked only on the 1st click (after) page rendered, now when I close the dialog and click on the open dialog link again, it gave a $().dialog('open') not defined error.

I got it to work with your solutions plus I also added the CSS files for the widget with this code:

public function renderOnRequest() {

        $html = '';
        foreach ($this->scriptFiles as $scriptFiles) {
            foreach ($scriptFiles as $scriptFile)
                $html.=CHtml::scriptFile($scriptFile) . "\n";
        }

        // Addition to register CSS files
        foreach ($this->cssFiles as $key => $value) {

            $html .= CHtml::cssFile($key) . "\n";
        }

        foreach ($this->scripts as $script)
            $html.=CHtml::script(implode("\n", $script)) . "\n";

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

0

#40 User is offline   nlac 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 7
  • Joined: 26-April 11
  • Location:Hungary

Posted 02 June 2011 - 04:01 PM

Hi, maybe you'll find it also useful: http://www.yiiframew...lsclientscript/
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