October: using file upload widget in a popup

Created on 1 Mar 2017  路  9Comments  路  Source: octobercms/october

Expected behavior

( upload and attach files to model as we use fileupload in create or update pages)

Actual behavior

(I render a form from yaml config file in a popup window every thing works correctly but as i choose a file to upload it upload the file but when i click on delete or edit file the system will throw " a widget with class name 'dashboardFiles' has not been bound to the controller" and form does not send the file to save method)

this is my stack trace data:

exception 'October\Rain\Exception\SystemException' with message 'A widget with class name 'dashboardFiles' has not been bound to the controller' in /opt/lampp/htdocs/imis-lawyer/modules/backend/classes/Controller.php:517
Stack trace:

0 /opt/lampp/htdocs/imis-lawyer/modules/backend/classes/Controller.php(423): Backend\Classes\Controller->runAjaxHandler('dashboardFiles:...')

1 /opt/lampp/htdocs/imis-lawyer/modules/backend/classes/Controller.php(233): Backend\Classes\Controller->execAjaxHandlers()

2 /opt/lampp/htdocs/imis-lawyer/modules/backend/classes/BackendController.php(106): Backend\Classes\Controller->run('index', Array)

3 [internal function]: Backend\Classes\BackendController->run('imis/processman...')

4 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(256): call_user_func_array(Array, Array)

5 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(164): Illuminate\Routing\Controller->callAction('run', Array)

6 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(112): Illuminate\Routing\ControllerDispatcher->call(Object(Backend\Classes\BackendController), Object(Illuminate\Routing\Route), 'run')

7 [internal function]: Illuminate\Routing\ControllerDispatcher->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))

8 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

9 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

10 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

11 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(114): Illuminate\Pipeline\Pipeline->then(Object(Closure))

12 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(69): Illuminate\Routing\ControllerDispatcher->callWithinStack(Object(Backend\Classes\BackendController), Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'run')

13 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Route.php(203): Illuminate\Routing\ControllerDispatcher->dispatch(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request), 'Backend\Classes...', 'run')

14 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Route.php(134): Illuminate\Routing\Route->runWithCustomDispatcher(Object(Illuminate\Http\Request))

15 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Router.php(708): Illuminate\Routing\Route->run(Object(Illuminate\Http\Request))

16 [internal function]: Illuminate\Routing\Router->Illuminate\Routing{closure}(Object(Illuminate\Http\Request))

17 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

18 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

19 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

20 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Router.php(710): Illuminate\Pipeline\Pipeline->then(Object(Closure))

21 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Router.php(675): Illuminate\Routing\Router->runRouteWithinStack(Object(Illuminate\Routing\Route), Object(Illuminate\Http\Request))

22 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Routing/Router.php(635): Illuminate\Routing\Router->dispatchToRoute(Object(Illuminate\Http\Request))

23 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(236): Illuminate\Routing\Router->dispatch(Object(Illuminate\Http\Request))

24 [internal function]: Illuminate\Foundation\Http\Kernel->Illuminate\Foundation\Http{closure}(Object(Illuminate\Http\Request))

25 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(139): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

26 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

27 [internal function]: Illuminate\View\Middleware\ShareErrorsFromSession->handle(Object(Illuminate\Http\Request), Object(Closure))

28 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)

29 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(62): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

30 [internal function]: Illuminate\Session\Middleware\StartSession->handle(Object(Illuminate\Http\Request), Object(Closure))

31 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)

32 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

33 [internal function]: Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse->handle(Object(Illuminate\Http\Request), Object(Closure))

34 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)

35 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(59): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

36 [internal function]: Illuminate\Cookie\Middleware\EncryptCookies->handle(Object(Illuminate\Http\Request), Object(Closure))

37 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)

38 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(44): Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

39 [internal function]: Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode->handle(Object(Illuminate\Http\Request), Object(Closure))

40 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(124): call_user_func_array(Array, Array)

41 [internal function]: Illuminate\Pipeline\Pipeline->Illuminate\Pipeline{closure}(Object(Illuminate\Http\Request))

42 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(103): call_user_func(Object(Closure), Object(Illuminate\Http\Request))

43 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(122): Illuminate\Pipeline\Pipeline->then(Object(Closure))

44 /opt/lampp/htdocs/imis-lawyer/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(87): Illuminate\Foundation\Http\Kernel->sendRequestThroughRouter(Object(Illuminate\Http\Request))

45 /opt/lampp/htdocs/imis-lawyer/index.php(44): Illuminate\Foundation\Http\Kernel->handle(Object(Illuminate\Http\Request))

46 {main}

screenshot from 2017-03-01 23-18-25

and this is my formCreate method:
public function onCreateForm() { $dashboard_id = post('dashboard_id'); $level_id = post('level_id'); if($this->checkPermission($level_id)){ $dashboardModel = Dashboard::find($dashboard_id); $nextLevel = $dashboardModel->processLevel->processType->processLevels()->where('level_priority',$dashboardModel->processLevel->level_priority+1)->first(); $config = $this->makeConfig($this->levelManager); $config->model = new \Imis\ProcessManagement\Models\Dashboard; $config->alias = 'dashboard'; $config->arrayName = 'Dashboard'; $widget = $this->makeWidget('Backend\Widgets\Form', $config); $widget->bindToController(); $this->vars['widget'] = $widget; $this->vars['dashboard_id'] = $dashboard_id; $this->vars['dashboard_model'] = $dashboardModel; if($nextLevel){ $this->vars['next_level'] = $nextLevel; } return $this->makePartial('levelmanager/level_manager'); }else{ return $this->onShowPassed(); } }

Thank you.

Question

Most helpful comment

@salehasadi That's your problem then, you need to run the method on every request to that controller, otherwise your widget isn't actually going to exist when any AJAX requests are made to that controller.

So, for example, you could run your initCustomFormWidget() method from within your update() or create() method so that it gets run on every request, AJAX or otherwise, that is made to that particular context.

Then, you would have a separate onRenderCustomFormWidget() that would actually render the widget and return it as a partial. Here's a quick example of something that I'm using for this:

public $threadListWidget;
public function initThreadList($message, $user = null)
{
    $listConfig = $this->makeConfig('$/look/conversation/controllers/configs/list.thread.yaml');
    $columnConfig = $this->makeConfig($listConfig->list);
    $columnConfig->model = $message;
    $columnConfig->alias = 'ThreadList';

    /*
     * Prepare the columns configuration
     */
    $configFieldsToTransfer = [
        'recordUrl',
        'recordOnClick',
        'recordsPerPage',
        'noRecordsMessage',
        'defaultSort',
        'showSorting',
        'showSetup',
        'showCheckboxes',
        'showTree',
        'treeExpanded',
        'customViewPath',
    ];

    foreach ($configFieldsToTransfer as $field) {
        if (isset($listConfig->{$field})) {
            $columnConfig->{$field} = $listConfig->{$field};
        }
    }

    $columnConfig->recordOnClick = "$.oc.threadBehavior.clickMessage(':id')";

    $widget = $this->makeWidget('Backend\Widgets\Lists', $columnConfig);
    $widget->addFilter(function ($query) use ($message, $user) {
        return $query->siblings($message, $user);
    });
    $widget->bindEvent('list.extendColumns', function () use ($widget) {
        // TODO: IMPORTANT: Reorder final columns array to put columns in correct order (atts, preview, from, to, created_at - improve this interface in general.
        // TODO: Need to redirect any message that isn't the most recent in the thread to the most recent and provide a popup model for previewing other messages in the thread
        $unhideColumns = ['from', 'recipientNames'];
        $replacementColumns = [];
        foreach ($unhideColumns as $unhide) {
            $replacementColumns[$unhide] = $widget->columns[$unhide];
            $replacementColumns[$unhide]['invisible'] = false;
            $widget->removeColumn($unhide);
        }

        $widget->removeColumn('subject_with_thread_count');

        $widget->addColumns($replacementColumns);
    });

    $this->threadListWidget = $widget;
    $this->addJs('/plugins/look/conversation/assets/js/threads.js');
}

protected $messagePopup;
public function onThreadClickMessage()
{
    $messageId = post('messageId');
    $this->messagePopup = true; // signal that the context is a message popup
    $this->controller->preview($messageId);

    return $this->makePartial('$/look/conversation/controllers/partials/popup.message.htm');
}

All 9 comments

:-| no one!? :-\

I can't read your code example because you used a single backtick.

Use three backticks so that the formatting is preserved. I don't have time to try to read messy code :(

thanks for your reply and sorry for that messy code ;-)

Have you looked into the FormController behavior to see what it does to initialize the formwidgets? I feel like there's supposed to be a call to an init() method somewhere.

it has an initForm() method. i called that method in index. I don't know what should I do exactly.

@salehasadi When do you run the method that sets up your widget? You need to make sure that the widget gets set up correctly on all requests that will be made to it, not just the initial request that renders it.

@LukeTowers I run the method as i click on a " button " to show popup window.

@salehasadi That's your problem then, you need to run the method on every request to that controller, otherwise your widget isn't actually going to exist when any AJAX requests are made to that controller.

So, for example, you could run your initCustomFormWidget() method from within your update() or create() method so that it gets run on every request, AJAX or otherwise, that is made to that particular context.

Then, you would have a separate onRenderCustomFormWidget() that would actually render the widget and return it as a partial. Here's a quick example of something that I'm using for this:

public $threadListWidget;
public function initThreadList($message, $user = null)
{
    $listConfig = $this->makeConfig('$/look/conversation/controllers/configs/list.thread.yaml');
    $columnConfig = $this->makeConfig($listConfig->list);
    $columnConfig->model = $message;
    $columnConfig->alias = 'ThreadList';

    /*
     * Prepare the columns configuration
     */
    $configFieldsToTransfer = [
        'recordUrl',
        'recordOnClick',
        'recordsPerPage',
        'noRecordsMessage',
        'defaultSort',
        'showSorting',
        'showSetup',
        'showCheckboxes',
        'showTree',
        'treeExpanded',
        'customViewPath',
    ];

    foreach ($configFieldsToTransfer as $field) {
        if (isset($listConfig->{$field})) {
            $columnConfig->{$field} = $listConfig->{$field};
        }
    }

    $columnConfig->recordOnClick = "$.oc.threadBehavior.clickMessage(':id')";

    $widget = $this->makeWidget('Backend\Widgets\Lists', $columnConfig);
    $widget->addFilter(function ($query) use ($message, $user) {
        return $query->siblings($message, $user);
    });
    $widget->bindEvent('list.extendColumns', function () use ($widget) {
        // TODO: IMPORTANT: Reorder final columns array to put columns in correct order (atts, preview, from, to, created_at - improve this interface in general.
        // TODO: Need to redirect any message that isn't the most recent in the thread to the most recent and provide a popup model for previewing other messages in the thread
        $unhideColumns = ['from', 'recipientNames'];
        $replacementColumns = [];
        foreach ($unhideColumns as $unhide) {
            $replacementColumns[$unhide] = $widget->columns[$unhide];
            $replacementColumns[$unhide]['invisible'] = false;
            $widget->removeColumn($unhide);
        }

        $widget->removeColumn('subject_with_thread_count');

        $widget->addColumns($replacementColumns);
    });

    $this->threadListWidget = $widget;
    $this->addJs('/plugins/look/conversation/assets/js/threads.js');
}

protected $messagePopup;
public function onThreadClickMessage()
{
    $messageId = post('messageId');
    $this->messagePopup = true; // signal that the context is a message popup
    $this->controller->preview($messageId);

    return $this->makePartial('$/look/conversation/controllers/partials/popup.message.htm');
}

thanks @LukeTowers that was the point.

Was this page helpful?
0 / 5 - 0 ratings