【问题标题】:SilverStripe - Maintain dropdown selected content when hitting back buttonSilverStripe - 点击返回按钮时保持下拉选择的内容
【发布时间】:2016-07-01 15:52:46
【问题描述】:

我有一个文章列表,可以根据年份的下拉列表按年份排序。我问了这个问题并得到了一个惊人的答案,但现在我注意到一个问题:每当用户单击“返回”时,文章列表总是重置为默认视图(即显示所有文章)。但是,下拉列表“记住”用户所做的选择。我希望文章列表与下拉列表中的选择年份相匹配,以使用户保持一致和轻松(我不希望他们每次点击文章上的后退按钮时都必须重新选择最初选择的年份) .

我知道我可以使用会话变量,但我想知道这是否真的有必要?或者考虑到代码的设置方式,这可能是更容易采取的方法?

这是我的 NewsReleasesPage 模板的代码:

<?php

class NewsReleasesPage extends Page
{
    private static $db = array();

    private static $has_one = array();
}

class NewsReleasesPage_Controller extends Page_Controller
{
    private static $allowed_actions = array(
        'PaginatedReleases',
        'YearFilterForm',
        'handleYearRequest',
        'doFilter',
        'year',
        'index'
    );

    public function init()
    {
        parent::init();
    }


    public function handleYearRequest(SS_HTTPRequest $request)
    {
        $year = $request->param('ID');
        $data = array(
            'Year' => $year,
            'PaginatedReleases' => $this->PaginatedReleases($year)
        );

        if ($request->isAjax()) {
            // in case of an ajax request, render only the partial template
            return $this->renderWith('ArticleList', $data);
        } else {
            // returning an array will cause the page to render normally
            return $data;
        }
    }

    //creates a form to filter through news releases by year
    public function YearFilterForm()
    {
        // get an array of all distinct years
        $list = SQLSelect::create()
            ->addFrom('NewsReleaseArticlePage')
            ->selectField('YEAR("ArticleDate")', 'Year')
            ->setOrderBy('Year', 'DESC')
            ->addGroupBy('"Year"')->execute()->column('Year');

        // create an associative array with years as keys & values
        $values = array_combine($list, $list);

        // our fields just contain the dropdown, which uses the year values
        $fields = FieldList::create(array(
            DropdownField::create(
                'Year',
                '',
                $values,
                $this->getRequest()->param('ID')
            )->setHasEmptyDefault(true)->setEmptyString('Show all')
        ));

        $actions = FieldList::create(array(
            FormAction::create('doFilter', 'Submit')
        ));

        return Form::create($this, 'YearFilterForm', $fields, $actions);
    }

    public function year()
    {
        return $this->handleYearRequest($this->request);
    }

    public function index()
    {
        return $this->handleYearRequest($this->request);
    }

    //redirects to the proper url depending on which year is selected for sorting news
    public function doFilter($data, $form)
    {
        if (empty($data['Year'])) {
            return $this->redirect($this->Link());
        } else {
            return $this->redirect($this->Link('year/' . $data['Year']));
        }
    }

    //created a paginated list of news released by year
    public function PaginatedReleases($year = null)
    {
        $list = NewsReleaseArticlePage::get()->sort('ArticleDate', 'DESC');
        if ($year) {
            $list = $list->where(array('YEAR("ArticleDate") = ?' => $year));
        }
        return PaginatedList::create($list, $this->getRequest())->setLimitItems(0);
    }

}

这是与此相关的jQuery:

(function($) {
    $(function(){
        // hide form actions, as we want to trigger form submittal
        // automatically when dropdown changes
        $("#Form_YearFilterForm").find(".Actions").hide();

        // bind a change event on the dropdown to automatically submit
        $("#Form_YearFilterForm").on("change", "select", function (e) {
            $("#Form_YearFilterForm").submit();
        });

        // handle form submit events
        $("#Form_YearFilterForm").on("submit", function(e){
            e.preventDefault();
            var form = $(this);
            $("#ArticleList").addClass("loading");
            // submit form via ajax
            $.post(
                form.attr("action"),
                form.serialize(),
                function(data, status, xhr){
                    $("#ArticleList").replaceWith($(data));
                }
            );
            return false;
        });

        // handle pagination clicks
        $("body").on("click", "a.pagination", function (e) {
            e.preventDefault();
            $("#ArticleList").addClass("loading");
            $.get(
                $(this).attr("href"),
                function(data, status, xhr){
                    $("#ArticleList").replaceWith($(data));
                }
            );

            return false;
        });

    });
})(jQuery);

然后是呈现列表的 SilverStripe 模板文件:

<div id="box3" class="clearfix">
    <div id="Box-Main-Right" class="clearfix">
        <p class="Text-Intro">$H1</p>
        $YearFilterForm
    </div>
</div>
<div class="Box-LEADING-BRANDS clearfix">
    <div class="Box-Main-Right1 clearfix">
        <% include ArticleList %>
    </div>
</div>
$Form

【问题讨论】:

    标签: php jquery silverstripe


    【解决方案1】:

    我认为您遇到了这个问题,因为表单在页面加载时以不同于默认状态的状态开始,因此内容(通过 JS 加载)与表单字段不同步。

    如果下拉列表值与默认值不同(例如,当它不是空值时),一个简单的(尽管有些 hacky)方法是通过 JS 提交表单。您可以通过如下更改您的 JS 代码来做到这一点:

    // handle form submit events
    $("#Form_YearFilterForm").on("submit", function(e){
        // removed code for brevity
    });
    
    // NEW CODE TO ADD
    // If the dropdown has a value (eg. is not empty), submit it.
    if($("#Form_YearFilterForm select").val()){
        $("#Form_YearFilterForm").submit();
    }
    

    这样做的正确方法是让您的 JavaScript 代码与 URL 更改一起工作。您可以通过使用History API 来做到这一点。所以你会重写你的JS代码如下:

    ;(function($) {
        $(function(){
            // Establish Variables
            var History = window.History,
                State = History.getState();
    
            // hide form actions, as we want to trigger form submittal
            // automatically when dropdown changes
            $("#Form_YearFilterForm .Actions").hide();
    
            // bind a change event on the dropdown to automatically submit
            $("#Form_YearFilterForm").on("change", 'select[name="Year"]', function(e){
                $("#Form_YearFilterForm").submit();
            });
    
            // handle form submit events
            $("#Form_YearFilterForm").on("submit", function(e){
                e.preventDefault();
                var dropdown = $(this).find('select[name="Year"]');
                var year = dropdown.val();
                // Add a new history state where we keep the year as a property
                // and use the urlpattern to build our target URL
                History.pushState(
                    { year: year },
                    null,
                    dropdown.data("urlpattern").replace(/YYYY$/, year)
                );
                return false;
            });
    
            History.Adapter.bind(window, 'statechange', function(){
                // Whenever the URL changes, we load the proper data via AJAX
                // and set the dropdown value accordingly
                State = History.getState();
                $('#Form_YearFilterForm select[name="Year"]').val(State.data.year);
                $("#ArticleList").addClass("loading");
                $.get(
                    State.url,
                    function(data, status, xhr){
                        $("#ArticleList").replaceWith($(data));
                    }
                );
            });
    
            // handle pagination clicks
            $("body").on("click", "a.pagination", function (e) {
                e.preventDefault();
                $("#ArticleList").addClass("loading");
                $.get(
                    $(this).attr("href"),
                    function(data, status, xhr){
                        $("#ArticleList").replaceWith($(data));
                    }
                );
    
                return false;
            });
        });
    })(jQuery);
    

    PHP 部分保持不变,除了一个小添加,我们将所需的 URL 模式传递给 JS。我将它作为 HTML5 数据属性添加到下拉字段中,但您可以对其进行硬编码或以其他方式传递它:

    DropdownField::create(
        'Year',
        'Year',
        $values,
        $this->getRequest()->param('ID')
    )->setHasEmptyDefault(true)
        ->setEmptyString('Show all')
        ->setAttribute('data-urlpattern', $this->Link('year') . '/YYYY')
    

    这个稍微复杂一点的解决方案的好处是,它可以识别 URL。因此,您可以使用后退/前进浏览器按钮正常导航,同时仍保留完整的 AJAX 功能。

    【讨论】:

    猜你喜欢
    • 2016-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-18
    • 2020-02-19
    • 1970-01-01
    • 2013-10-12
    相关资源
    最近更新 更多