在 null 上调用成员函数 setComponentContext() - OctoberCMS
Call to a member function setComponentContext() on null - OctoberCMS
在过去的几个月里,我一直在学习 PHP 并使用 Octobercms,但我对它还是很陌生。我要实现的基本概念是一个包含 5 个图块的页面。当我单击图块时,它会根据您单击的图块将当前页面替换为部分页面,并更改 url 而无需重新加载页面。每个图块都有一个 id,其中包含它应该 return 的部分名称。例如,设置图块有一个 data-id="settings"
。这是页面的屏幕截图
page
我为此创建了自己的插件并将该组件放置在页面上。在渲染它时 returns 仪表板部分可以正常工作并显示在上面的屏幕截图中,问题是当我单击另一个图块时。它调用 ajax 并在我的组件中调用我的 "test" 方法,并将包含部分名称的图块 ID 传递给 return。我使用 $this->renderPartial('partialName')
方法,但出现以下错误
the error
Call to a member function setComponentContext() on null
以下是我其余代码的屏幕截图:
My 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');
}
});
}
});
My Router.php
<?php
Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');
My Component
<?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') );
}
}
}
我试着做了一些测试,认为我已经找到了问题,但我真的不明白如何解决它。这里有一些额外的截图
我转储组件对象
testing component
在渲染上看起来不错
onRender
现在它是空的?
clicked settings page
这是处理 Ajax 请求的错误方式,因为您正在破坏 October CMS 页面的生命周期。
您收到错误是因为您直接要求组件处理请求 Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');
因为 renderpartial
需要控制器上下文,如果你这样做 route
它肯定会 yield unexpected behaviour
Ok, We get this, BUT then , How to do it correctly ?
Your url lets say we use like this /planner/:type
Add framework and extra to sure layout for ajax-framework [ make sure you add them before your script ]
<script src="{{ 'assets/javascript/jquery.js'|theme }}"></script>
{% framework extras %}
Your script should look like this
<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>
Your Component
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')];
}
}
Your patials
文件:_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>
Initially it will render default partial dashboard
if no type
is passed
dashboard
与 other tile partials
.
的所有其他 tile links
和 dashboard content
相同
现在如果你 click any tile
它会 fire October Ajax framework request
处理程序 onRenderTile
和 type (dashboard|tile1|tile2 ...)
所以它会正确调用 October lifecycle methods
并最终通过 [= 呈现部分31=] 和 return json 键 #tile-area
并且作为值它将 return content of posted partial name(type)
OctoberCMS ajax framework
足够聪明,它只会用给定的 id 替换此内容,因此它会搜索 #tile-area
并用新内容替换它的内容。
有关使用 ajax
更新部分的更多信息,您可以阅读此内容:https://octobercms.com/docs/ajax/update-partials
如有任何疑问或问题,请发表评论。
在过去的几个月里,我一直在学习 PHP 并使用 Octobercms,但我对它还是很陌生。我要实现的基本概念是一个包含 5 个图块的页面。当我单击图块时,它会根据您单击的图块将当前页面替换为部分页面,并更改 url 而无需重新加载页面。每个图块都有一个 id,其中包含它应该 return 的部分名称。例如,设置图块有一个 data-id="settings"
。这是页面的屏幕截图
page
我为此创建了自己的插件并将该组件放置在页面上。在渲染它时 returns 仪表板部分可以正常工作并显示在上面的屏幕截图中,问题是当我单击另一个图块时。它调用 ajax 并在我的组件中调用我的 "test" 方法,并将包含部分名称的图块 ID 传递给 return。我使用 $this->renderPartial('partialName')
方法,但出现以下错误
the error
Call to a member function setComponentContext() on null
以下是我其余代码的屏幕截图:
My 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');
}
});
}
});
My Router.php
<?php
Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');
My Component
<?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') );
}
}
}
我试着做了一些测试,认为我已经找到了问题,但我真的不明白如何解决它。这里有一些额外的截图
我转储组件对象 testing component 在渲染上看起来不错 onRender 现在它是空的? clicked settings page
这是处理 Ajax 请求的错误方式,因为您正在破坏 October CMS 页面的生命周期。
您收到错误是因为您直接要求组件处理请求 Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');
因为 renderpartial
需要控制器上下文,如果你这样做 route
它肯定会 yield unexpected behaviour
Ok, We get this, BUT then , How to do it correctly ?
Your url lets say we use like this
/planner/:type
Add framework and extra to sure layout for ajax-framework [ make sure you add them before your script ]
<script src="{{ 'assets/javascript/jquery.js'|theme }}"></script>
{% framework extras %}
Your script should look like this
<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>
Your Component
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')];
}
}
Your patials
文件:_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>
Initially it will render
default partial dashboard
if notype
is passed
dashboard
与 other tile partials
.
tile links
和 dashboard content
相同
现在如果你 click any tile
它会 fire October Ajax framework request
处理程序 onRenderTile
和 type (dashboard|tile1|tile2 ...)
所以它会正确调用 October lifecycle methods
并最终通过 [= 呈现部分31=] 和 return json 键 #tile-area
并且作为值它将 return content of posted partial name(type)
OctoberCMS ajax framework
足够聪明,它只会用给定的 id 替换此内容,因此它会搜索 #tile-area
并用新内容替换它的内容。
有关使用 ajax
更新部分的更多信息,您可以阅读此内容:https://octobercms.com/docs/ajax/update-partials
如有任何疑问或问题,请发表评论。