在null上调用成员函数setComponentContext()-OctoberCMS

时间:2018-10-13 13:34:41

标签: php oop octobercms octobercms-plugins

在过去的几个月中,我一直在学习PHP并使用Octobercms,但我仍然很陌生。我要实现的基本概念是一个包含5个图块的页面。当我单击图块时,它会根据您单击的图块来部分替换当前页面,并更改URL,而无需重新加载页面。每个图块都有一个ID,其中包含应返回的部分名称。例如,设置图块具有data-id="settings"。这是页面的屏幕截图

page

我为此创建了自己的插件,并将组件放置在页面上。在渲染时,它返回可以正常工作的仪表板部分,如上面的屏幕截图所示,问题是当我单击另一个图块时。它进行ajax调用并在组件中调用我的“ test”方法,并传递包含要返回的部分名称的tile ID。我使用方法$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

1 个答案:

答案 0 :(得分:0)

当您打破十月CMS页面的生命周期时,这是处理Ajax请求的错误方式。

收到错误消息是因为您直接要求组件处理请求Route::get('/planner/{page}', 'myName\budgetplanner\Components\app@test');

由于renderpartial需要控制器上下文,如果您这样做route,那么肯定会yield unexpected behaviour

  

好吧,我们明白了,但是然后,如何正确执行?


  

您的网址可以说我们像这样/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')];
    }
}
  

您的展位

文件:_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 linksdashboard contentother tile partials相同。

现在,如果您click any tilefire October Ajax framework request与处理程序onRenderTiletype (dashboard|tile1|tile2 ...)一起使用,那么它将正确调用October lifecycle methods并最终通过{{1} },并返回键为{{1}的 json ,其值为onRenderTile

#tile-area足够聪明,它只会用给定ID替换此内容,因此它将搜索return content of posted partial name(type)并将其内容替换为新的ID。

有关使用OctoberCMS ajax framework更新局部的更多信息,您可以阅读:https://octobercms.com/docs/ajax/update-partials

如有任何疑问或疑问,请发表评论。