ajax and widgets

I’m working on a widget, that does a lot of ajax calls to display data.

When I try to show a form through an ajax call from this widget,

some form elements will not work (CJuiDatePicker,…) because the javascript/clientScript code and the ‘js-bind’ is not submitted to the browser.

The problem is, that the main widget doesn’t have a ‘renderPartial’ like a controller, where I could set ‘processoutput=true’ to output the js-stuff.

A widget only has the render function without the possibility to output the generated registerClientScript code.

I didn’t test ‘$this->controller->renderPartial’ because the controller is not always the same and doesn’t know where to find the view file for the form and ‘$this’ in the view should be the widget itself not the controller.

Any idea how to solve this?

Hello

can you try with

renderPartial(Your_File_Name , array(Whatever data want to pass),false,true);

OR

renderPartial(Your_File_Name , ‘’ ,false,true);

Thanks

As I wrote, I did’t test it, because of the reasons explained above.

But if this is the only possible solution I have to give ‘$this->controller->renderPartial’ a try.

I don’t know what the purpose of your widget is but maybe it is better to create a CAction that can be used by all controllers using the widget (CAutoComplete does that if I am correct). This way the widget could use $this->controller->controllerActionName which does the renderPartial.

Greetings,

Hannes

The widget renders a input form and displays data by ajaxSubmit from this form.

For this purpose I have a CAction that handles the ajax responses.

In one of the ajax-call I want to reuse the widget-code to display the form as ajax-response, filled with specific values.

I just tried this




 //main view -> OK

  ...

  $this->widget('...FormWidget', array('model'=>$formModel));  //displays the form in the main view 







 //the CAction component that handles the ajax responses for the form widget

 

 class FormWidgetAction extends CAction

 {

    ....  

    

    // datepickers... doesn't work on ajax-response

    protected function renderUpdateForm()

    {

        $model = ...

        ...

        

   // I want to reuse the widget here to display the form filled with data ...

        $this->controller->widget('FormWidget', array('model'=>$model));

    }

 




    /**

     * Run the action

     */

    public function run()

    {


        if (Yii::app()->request->isAjaxRequest)

        {


            $action = isset($_GET['action']) ? $_GET['action'] : null;


            if (empty($action))

            {

                echo 'Param missing: action';

                Yii::app()->end();

            }


            switch ($action)

            {

               case 'updateform':

                    $this->renderUpdateForm();

                    break;


                case 'preview':

                    $this->renderPreview();

                    break;


                ....


                default:

                    echo 'Unknown action: ' . $action;

            }


            Yii::app()->end();

        }

    }


 } 




Just a random thought, but it might be worth giving it a try:


$this->controller->renderPartial('application.widgets.FormWidget.views.form',array('model'=>$model), false,true);

So instead of passing in a relative path you force the controller to use a specific view not located in its own views folder but somewhere else. In this case the view is located in your widgets views folder.

Hannes, thanks for your input, I have tested it, but I doesn’t work.

The reason:

In the form view, I call a lot of methods from the widget ($this->renderInputXY …) so $this should be the widget.

I have tried to submit the widget as ‘$this’:




  $widget = new FormWidget();

  $widget->init();


  $this->controller->renderPartial('application.widgets.FormWidget.views.form',array('this'=>$widget, 'model'=>$model), false,true);

  



But Yii doesn’t like this ‘trick’ on internal rendering :frowning:

But many thanks for the input.

I think the possible solution will be to use an iframe for the update form or I have to fully rewrite the view-file.

I hope (despite this problem) to publish my next extension (managing recurring events) next week.

I haven’t carefully read the entire thread but I think I could contribute a but here:

FWIW, I’m stuck on a similar problem: I have a module, which has a bundled widget within, and this widget is processing AJAX requests. Now, in order to render the views of this widget I’m doing something like:


$this->controller->renderPartial("application.modules.polls.extensions.PollWidget.views." . $this->_viewFile, array(...));

.

While this trick to get render partial works, it works partially. While rendering the page initially, everything works fine, but for some reason when the AJAX call is processed, the entire page is rendered inside the small widget box. I think this isn’t a big surprise as the same has happened when initial rendering of widget occurred.

I’m contemplating between two solutions:

[list=1][]Doing some manual processing of the needed view file, echo, and "Yii::app()->end() (or simply die()…).[]Creating some super CPortlet class that will contain a renderPartial() method, as described here.[/list]

Hope it helps someone.

Finally I solved this in a very simple way.

The steps to solve this are the following.

[list=1]

[*]Render your widget in the controller and make sure you capture the output setting the last parameter to true


$html = $this->widget( $className,  $properties=array ( ), TRUE)

[*]Render your scripts with the help of the client script.


Yii::app()->getClientScript()->renderBodyBegin($html);

Yii::app()->getClientScript()->renderBodyEnd($html);

[*] Happily echo your output and end the app


echo CJSON::encode(array( 'html' => $html)); //I echo as Json as I will need that in my ajax javascript functions later on.

                Yii::app()->end();

[/list]

Thats it. The html variable you pass will be used as a reference by the client script and the corresponding script tags will be added to the html body.

Some background info of why this worked for me

I have a button that goes to a controller action, the action does some work and then renders a widget again to return to the view. The widget has some ajaxButtons and it renders some other widgets that also need some scripts to validate some forms. When I rendered the view for the first time, everything worked but when the widgets where rendered on the ajax call, they would not bring back the scripts therefore nothing worked anymore.

You may use the render method of the client script as an alternative, but this will also make the view retrieve the core scripts again (such as jquery and yiiactiveform). That is why I use the renderBodyBegin and renderBodyEnd instead, because I already have those scripts rendered in the view from the initial request.

I hope this solution works for someone. I am very happy and everything works for me now =)

interesting solution, i dont get where are you executing all this code ? in the same controller ? right ? :)

Yes, that is correct.