php - SilverStripe - 根据下拉选择创建分页

标签 php jquery pagination silverstripe

我正在为 SilverStripe 网站上的页面构建一些分页,默认情况下首先显示所有文章,但用户可以通过从下拉控件中选择年份来选择要查看的文章。

这是文章的模板。现在我有代码在页面首次加载或重新加载时添加分页,并且所有文章都是从服务器获取的:

<select id="SelectNewsYear">
    <option value="">Select a year</option>
    <% loop $GroupedNewsByDate.GroupedBy(PublishYear) %>
        <option value="$PublishYear">$PublishYear</option>
    <% end_loop %>
    <option value="all">Show all</option>
</select>
<br /><br />

<div class="RecentNews">
    <% loop $PaginatedReleases %>
       $ArticleDate.format("F j, Y"), <a href="$URLSegment">$H1</a><br />
    <% end_loop %>

    <% if $PaginatedReleases.MoreThanOnePage %>
        <% if $PaginatedReleases.NotFirstPage %>
            <a class="prev" href="$PaginatedReleases.PrevLink">Prev</a>
        <% end_if %>
        <% loop $PaginatedReleases.Pages %>
            <% if $CurrentBool %>
                $PageNum
            <% else %>
                <% if $Link %>
                    <a href="$Link">$PageNum</a>
                <% else %>
                    ...
                <% end_if %>
            <% end_if %>
        <% end_loop %>
        <% if $PaginatedReleases.NotLastPage %>
            <a class="next" href="$PaginatedReleases.NextLink">Next</a>
        <% end_if %>
    <% end_if %>
</div>

Page.php中的PaginatedReleases函数:

//Returns a paginted list of news releases
public function PaginatedReleases(){
    $newslist = NewsReleaseArticlePage::get()->sort('ArticleDate', "DESC");
    return new PaginatedList($newslist, $this->getRequest());
}

现在的问题是如何在从下拉列表中选择年份时保持分页功能。最初,我并不关心分页,因为我更关心下拉列表的功能。这是我目前设置的 jQuery 和 AJAX 代码,它从下拉列表中获取年份值并将其传递给服务器以执行相应的函数:

(function($) {
    $(document).ready(function() {

        var SelectNewsYear = $('#SelectNewsYear');

        var month = new Array();
        month[0] = "January";
        month[1] = "February";
        month[2] = "March";
        month[3] = "April";
        month[4] = "May";
        month[5] = "June";
        month[6] = "July";
        month[7] = "August";
        month[8] = "September";
        month[9] = "October";
        month[10] = "November";
        month[11] = "December";


        SelectNewsYear.change(function() {

            if (SelectNewsYear.val() != "" && SelectNewsYear.val() != null &&  SelectNewsYear.find('option:selected').attr('value') !="all") {
                sendYear();
            }
            else{
                showAll();
            }
        });

        //get all articles by the year selected
        function sendYear(){
            var year = SelectNewsYear.find('option:selected').attr('value');
            $.ajax({
                type: "POST",
                url: "/home/getNewsByYear/"+year,
                dataType: "json"
            }).done(function (response) {
                var list = '';
                var newsSection = $('.RecentNewsByYear');

                for (var i=0;i<response.length;i++){
                    var newsDate = new Date(response[i].date);
                    var monthFullName = month[newsDate.getUTCMonth()];

                    list += monthFullName + " " + newsDate.getUTCDate() +", " +newsDate.getFullYear()  + ', ' + '<a href="' + response[i].article + '"target="_blank">' + response[i].title +"</a> <br />";
                }
                newsSection.empty();
                newsSection.append(list);
            });
        }

    });
}(jQuery));

$ = jQuery.noConflict();

以及 Page.php 中的 getNewsByYear 函数:

//Get all recent news by year based on selected year from dropdown
    public function getNewsByYear(){
        //Get the year selected by the dropdown
        $newsReleaseYear = $this->getRequest()->param('ID');

        //Group together all news that are associated with that selected year
        $newsReleases = NewsReleaseArticlePage::get();

        $return = array();

        //put the news releases into the array that match the selected year
        foreach($newsReleases as $newsRelease){
            $newsDate = date("Y", strtotime($newsRelease->ArticleDate));

            if($newsDate == $newsReleaseYear){
                $return[] = array(
                    'title' => $newsRelease->H1,
                    'date' => $newsRelease->ArticleDate,
                    'article' => $newsRelease->URLSegment
                );
            }
        }

        return json_encode($return);
    }

getNewsByYear 函数按原样运行良好,但我不确定如何在此处合并 SilverStripe PaginationList 功能。我想知道是否有一种方法可以在不依赖 json 编码数据的情况下返回所选文章?

最佳答案

当您返回 JSON 以从 JSON 构建 HTML 标记时,肯定有改进的余地……

我还认为,以一种无需 JS 即可运行的方式编写您的应用程序逻辑,然后添加 JS 以逐步增强您的应用程序是一种很好的做法。这样您就不会将每个非 JS 设备/阅读器/用户拒之门外。

所以这就是我要做的(准备广泛的回答):

启用按年份过滤

首先,您希望能够按年份过滤您的记录。我认为您通过 URL 启用过滤的方法很好,所以这就是我们要做的:

1。获取分页列表,可选择按年份过滤

在您的 Controller 中,添加/修改以下方法:

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());
}

这将允许您通过传入 $year 获取所有条目,或仅获取特定年份的条目。参数。

2。将一年的 Action 添加到您的 Controller

public static $allowed_actions = array(
    'year' => true
);

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

运行后dev/build ,您应该已经能够通过更改 URL(例如 mypage/year/2016mypage/year/2015 等)按年份过滤您的条目

使用带有下拉列表的表单进行过滤

将以下内容添加到您的 Controller 以创建一个表单来过滤您的条目:

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',
            'Year',
            $values,
            $this->getRequest()->param('ID')
        )->setHasEmptyDefault(true)->setEmptyString('(all)')
    ));

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

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

实现doFilter功能。它只是重定向到正确的 URL,具体取决于选择的年份:

public function doFilter($data, $form)
{
    if(empty($data['Year'])){
        return $this->redirect($this->Link());
    } else {
        return $this->redirect($this->Link('year/' . $data['Year']));
    }
}

不要忘记将表单名称添加到 allowed_actions :

public static $allowed_actions = array(
    'YearFilterForm' => true, // <- this should be added!
    'year' => true
);

现在删除你的<select>从您的模板输入字段并将其替换为:$YearFilterForm .

运行后dev/build ,您应该有一个页面,其中包含允许按年份过滤的表单(具有工作分页)

启用 AJAX

使用 AJAX,我们希望能够只加载页面的更改部分。因此,首先要做的是:

1。为应该异步加载的内容创建一个单独的模板

创建模板 Includes/ArticleList.ss

<div id="ArticleList" class="RecentNews">
    <% loop $PaginatedReleases %>
       $ArticleDate.format("F j, Y"), <a href="$URLSegment">$H1</a><br />
    <% end_loop %>

    <% if $PaginatedReleases.MoreThanOnePage %>
        <% if $PaginatedReleases.NotFirstPage %>
            <a class="prev pagination" href="$PaginatedReleases.PrevLink">Prev</a>
        <% end_if %>
        <% loop $PaginatedReleases.Pages %>
            <% if $CurrentBool %>
                $PageNum
            <% else %>
                <% if $Link %>
                    <a href="$Link" class="pagination">$PageNum</a>
                <% else %>
                    ...
                <% end_if %>
            <% end_if %>
        <% end_loop %>
        <% if $PaginatedReleases.NotLastPage %>
            <a class="next pagination" href="$PaginatedReleases.NextLink">Next</a>
        <% end_if %>
    <% end_if %>
</div>

然后您的页面模板可以精简为:

$YearFilterForm
<% include ArticleList %>

dev/build 之后,一切都应该像以前一样工作。

2。当通过 AJAX 请求页面时,提供部分内容

因为这会影响对 year 的调用和 index (未过滤的条目),在您的 Controller 中创建一个辅助方法,如下所示:

protected 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;
    }
}

然后您可以添加/修改 indexyear看起来相同的方法:

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

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

3。用一些 JavaScript 连接一切

(function($) {
    $(function(){
        // 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", 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);

结论

您现在有了一个可以在非 JS 设备上正常降级的解决方案。通过下拉菜单和分页进行过滤是启用 AJAX 的。标记未在 JS 模板中定义,它只是负责标记的 SilverStripe 模板。

剩下要做的就是在内容刷新时添加漂亮的加载动画 ;)

关于php - SilverStripe - 根据下拉选择创建分页,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37685842/

相关文章:

php - 在 PHP 中,你可以在同一行实例化一个对象并调用一个方法吗?

php - 如何查找子字符串并删除周围的P标签

javascript - 将表格内的行显示到 <p> 下有一个文本区域

javascript - 如何从 jquery 中的 slider 中删除分页?

html - 将分页扩展到全宽?

php - 如何在php中使用字符串索引动态创建数组

javascript - 带有 map 代理脚本的 OpenLayers XYZ 示例

jquery - 如何在 Web api MVC 6 中启用跨域请求

jquery - 向上滚动时动画的元素,向下滚动时反转的元素

javascript - 使用 sprite 对 jQuery slider 进行分页时遇到问题