Вызов функции-члена setComponentContext() для null - OctoberCMS
Последние пару месяцев я изучаю PHP и использую Octobercms, и я все еще довольно новичок в этом. Основная концепция того, чего я пытаюсь достичь - это страница, которая содержит 5 плиток. Когда я щелкаю плитку, она заменяет текущую страницу частичной в зависимости от того, какую плитку вы щелкнули, и изменяет URL-адрес без перезагрузки страницы. у каждой плитки есть идентификатор с именем части, которую она должна вернуть. например, плитка настроек имеет data-id="settings"
, Вот скриншот страницы
Я создал свой собственный плагин для этого и разместил компонент на странице. При рендеринге возвращается часть панели инструментов, которая работает и показана на скриншоте выше, проблема в том, что я нажимаю другую плитку. Он выполняет вызов ajax и вызывает мой "тестовый" метод в моем компоненте и передает идентификатор тайла, который содержит имя партиала для возврата. Я использую метод $this->renderPartial('partialName')
Однако я получаю следующую ошибку
Call to a member function setComponentContext() on null
Вот скриншоты для остальной части моего кода:
$( 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');
}
});
}
});
<?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') );
}
}
}
Я попытался провести некоторое тестирование и думаю, что нашел проблему, но я не совсем понимаю, как ее исправить. вот несколько дополнительных скриншотов
Я выкидываю компонент, тестирующий компонент. При рендеринге он выглядит нормально, теперь он пустой. нажал страницу настроек
1 ответ
Это неправильный способ обработки Ajax-запросов, поскольку вы нарушаете жизненный цикл CMS-страницы October.
вы получаете ошибку, потому что вы напрямую запрашиваете компонент для обработки запроса Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');
как renderpartial
нужен контекст контроллера, и если вы делаете route
так будет yield unexpected behaviour
Хорошо, мы получаем это, НО тогда, как это сделать правильно?
Ваш URL, скажем, мы используем, как это
/planner/:type
Добавьте фреймворк и дополнительные, чтобы обеспечить верстку для 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')];
}
}
Ваши патиалы
файл: _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
если есть сомнения или вопрос, пожалуйста, прокомментируйте.