Вызов функции-члена setComponentContext () для null - OctoberCMS - PullRequest
0 голосов
/ 13 октября 2018

За последние пару месяцев я изучал PHP и использовал Octobercms, и я все еще довольно новичок в этом.Основная концепция того, чего я пытаюсь достичь - это страница, которая содержит 5 плиток.Когда я щелкаю плитку, она заменяет текущую страницу частичной в зависимости от того, какую плитку вы щелкнули, и изменяет URL-адрес без перезагрузки страницы.у каждой плитки есть идентификатор с именем части, которую она должна вернуть.например, плитка настроек имеет data-id="settings".Вот скриншот страницы

page

Я создал свой собственный плагин для этого и разместил компонент на странице.При рендеринге возвращается часть панели инструментов, которая работает и показана на скриншоте выше, проблема в том, что я нажимаю другую плитку.Он выполняет вызов ajax и вызывает мой «тестовый» метод в моем компоненте и передает идентификатор тайла, который содержит имя партиала для возврата.Я использую метод $this->renderPartial('partialName'), однако я получаю следующую ошибку

ошибка

Call to a member function setComponentContext() on null

Вот скриншоты для остальной части моего кода:

Мой Javascript

$( document ).ready(function() {

    $(document).on('click','.tile',function() {

        let page = $(this).attr('id');

        history.pushState({page}, '', 'planner/' + page );

        getPage(page);

    });

    window.onpopstate = function(e){

        if(e.state){
        getPage(e.state.id);
    }

    };

    history.replaceState({page: null}, 'Default state', './planner');

    function getPage (page) {

        $.ajax({
            url: '/planner/' + page,
            type: 'GET',
            success: function(data){
                $('.page-container').html(data);
            },
            error: function(data) {
                console.log('Could not return page');
            }
        });

    }



});

Мой Router.php

<?php

Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');

Мой компонент

<?php

namespace myName\budgetplanner\Components;

use Db;

class app extends \Cms\Classes\ComponentBase
{
    public function componentDetails()
    {
      return [
            'name' => 'budgetplanner',
            'description' => 'Manage your finances.'
        ];
    }

    public function onRender()
    {
      echo ( $this->renderPartial('@dashboard.htm') );
    }

    public function test($page)
    {

      if ($page == 'undefined') {
        echo ( $this->renderPartial('@dashboard.htm') );
      }
      elseif ($page == 'overview') {
        echo ( $this->renderPartial('@overview.htm') );
      }
      elseif ($page == 'month') {
        echo ( $this->renderPartial('@month.htm') );
      }
      elseif ($page == 'reports') {
        echo ( $this->renderPartial('@reports.htm') );
      }
      elseif ($page == 'budget') {
        echo ( $this->renderPartial('@budget.htm') );
      }
      elseif ($page == 'settings') {
        echo ( $this->renderPartial('@settings.htm') );
      }

    }

}

Я попытался провести некоторое тестирование и думаю, что нашел проблему, но я не совсем понимаю, как ее исправить.Вот некоторые дополнительные снимки экрана

Я сбрасываю объект компонента Проверка компонента При рендеринге все выглядит хорошо onRender теперь он пуст? нажал страницу настроек

1 Ответ

0 голосов
/ 15 октября 2018

Это неправильный способ обработки Ajax-запроса, поскольку вы нарушаете жизненный цикл страницы CMS за октябрь.

вы получаете сообщение об ошибке, потому что вы напрямую просите компонент обработать запрос Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');

как renderpartial нужен контекст контроллера, и если вы сделаете route, как это, он обязательно yield unexpected behaviour

Хорошо, мы получим это, НО тогда, Как это сделать правильно?


Ваш URL, скажем, используется таким образом /planner/:type

enter image description here

Добавление фреймворка и дополнения к верному макету для ajax-framework [, убедитесь, что вы добавили их перед вашим скриптом ]

<script src="{{ 'assets/javascript/jquery.js'|theme }}"></script>
{% framework extras %}

Ваш скрипт должен выглядеть следующим образомэто

<script>
$(document).ready(function() {

    $(document).on('click','.tile',function() {

        let page = $(this).attr('data-tile');
        history.pushState({page}, '', '/planner/' + page );
        getPage(page);
    });

    window.onpopstate = function(e){       
        if(e.state){
            getPage(e.state.page);
        }
    };
    // not sure causing issues so commented
    // history.replaceState({page: null}, 'Default state', './planner');
    function getPage (page) {
        $.request('onRenderTile', { data: { type: page }})
    }
});
</script>

Ваш компонент

public function onRender()
{
    // if type is not passed default would be dashboard
    $type = $this->param('type', 'dashboard');
    return $this->onRenderTile($type)['#tile-area'];
}

public function onRenderTile($type = null)
{
    $availableTiles = [
        'dashboard',
        'tile1',
        'tile2',
        'tile3',
    ];

    // if not passed any value then also check post request
    if(empty($type)) {
        $type = post('type');
    }

    // we check partial is valid other wise just return dashboard content
    if(in_array($type, $availableTiles)) {
        return ['#tile-area' => $this->renderPartial('@'.$type.'.htm')];
    }
    else {
        return ['#tile-area' => $this->renderPartial('@dashboard.htm')];
    }
}

Ваши двоечники

file: _tiles.htm

<div class="tile" data-tile="dashboard">Dashboard</div>
<div class="tile" data-tile="tile1">Tile 1</div>
<div class="tile" data-tile="tile2">Tile 2</div>
<div class="tile" data-tile="tile3">Tile 3</div>

файл: dashboard.htm

<div id="tile-area">
    {% partial __SELF__~"::_tiles" %}
    <h1>Dashboard</h1>
</div>

файл: tile1.htm

<div id="tile-area">
    {% partial __SELF__~"::_tiles" %}
    <h1>Tile 1 Content</h1>
</div>

файл: tile2.htm

<div id="tile-area">
    {% partial __SELF__~"::_tiles" %}
    <h1>Tile 2 Content</h1>
</div>

файл: tile3.htm

<div id="tile-area">
    {% partial __SELF__~"::_tiles" %}
    <h1>Tile 3 Content</h1>
</div>

Первоначально он будет отображать default partial dashboard, если не передано type

dashboard имеет все остальные tile links и dashboard content такие же, как other tile partials.

Теперь, если вы click any tile, он будет fire October Ajax framework request с обработчиком onRenderTile и type (dashboard|tile1|tile2 ...), поэтому он будет правильно вызывать October lifecycle methods и, наконец, визуализировать частичное с помощью onRenderTile и вернуть json с ключом #tile-area, и в качестве значения оно будет return content of posted partial name(type)

OctoberCMS ajax framework достаточно умным, чтобы просто заменить этот контентс указанием идентификатора, поэтому он будет искать #tile-area и заменяет свой контент новым.

для получения дополнительной информации об обновлении партиалов с помощью ajax вы можете прочитать это: https://octobercms.com/docs/ajax/update-partials

если есть сомнения или вопрос, пожалуйста, прокомментируйте.

...