(Solved) Jquery Sortable initialiization after Ajax Update

Hello everyone,

I’ve run into a problem and am looking for the best way to solve it without altering the Yii2 framework.

I have a page which contains elements that can be sorted. I’m using the yii-jui sortable widget and everything works fine after the initial view.

Under certain circumstances I need to update the content with all the elements per ajax. This too is working.

The problem is that when I update the content after an ajax call the jquery initialization for the sortable elements and their containers is lost.

When building the initial view the yii-jui extension places the javascript for initializing the Sortable elements in a Javascript block within an on-document-ready function. As I already stated this works fine during the first view. However, when I update the content the initializations are lost and somehow I need to run the javascript initialization again. I cannot do this because the on-document-ready function is not triggered.

A possible solution would be to place all the JS initialization for the sortable elements into a separate function and call this explicitly after the first view and also after an ajax update. The difficulty is that I see no way to do this with the yii-jui widget as it places all the initialization (events and options) as singular calls in the on-document-ready function.

I’ve considered the following:

  • Add an option to yii-jui widget to place the initialization steps into a JS function

  • Use a view event hook to manipulate the JS bundle/asset settings prior to building the HTML, so that I can create the function I need

  • Do not use the native options in the yii-jui widget but write a separate initialization script of my own.

Any ideas at how I could best proceed?

Thanks for any input

Andy Potter

I’ve found a solution.

By ‘hooking’ into the View EVENT_END_PAGE event I was able to alter the generated Javascript code and place it into a function.




    public function actionIndex()

    {

        $this->layout = 'main-full';

        Yii::$app->getUser()->setReturnUrl(Yii::$app->request->getUrl());

    

        $this->getView()->on(View::EVENT_END_PAGE, [$this, 'jsAsFunction']);

    

        return $this->render('index', [

            'board' => $this->currentBoard,

            'columnHtml' => $this->getColumnHtml(),

        ]);

    }

    

    public function jsAsFunction($event)

    {

        $event->sender->js[View::POS_HEAD] = ['var initializeBoard;'];

        $event->sender->js[View::POS_HEAD] = ['var longPollingTimeout = ' . self::LONG_POLLING_TIMEOUT . ';'];

        $event->sender->js[View::POS_READY] = array_merge(

            ['initializeBoard = function() {'],

            $event->sender->js[View::POS_READY],

            ['}'],

            ['initializeBoard();']

        );

    

        return true;

    }



When the View generates the Inline Javascript all the array elements are imploded together. So I just surrounded the code inside a function declaration. After that it is available at a later point.

Important

  • The function must be called explicitly after it has been declared

  • In order for the function to be available outside of the scope of jQuery(document).ready it must be assigned to a variable that has been declared with global scope. Thus the first two assignments that are generated into the <HEAD> area.