SilverStripe – 根据下拉选择创建分页

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

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

 Select a year  $PublishYear  Show all  

$ArticleDate.format("F j, Y"), $H1
$PageNum $PageNum ...

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

现在的问题是如何在从下拉列表中选择一年时确定如何保持分页function。 最初,我并不关心分页,因为我更关心下拉列表的function。 这是我目前设置的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() + ', ' + '' + response[i].title +" 
"; } 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 PaginationListfunction。 我想知道是否有办法在不依赖json编码数据的情况下返回所选文章?

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

我认为以不使用JS的方式编写应用程序逻辑是一种很好的做法,然后添加JS以逐步增强应用程序。 这样你就不会锁定每个非JS设备/阅读器/用户。

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

按年度启用过滤

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

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

在控制器中,添加/修改以下方法:

 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.向控制器添加年份操作

 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等)按年过滤您的条目。

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

将以下内容添加到控制器以创建表单以过滤条目:

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

现在从模板中删除输入字段,并将其替换为: $YearFilterForm

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

启用AJAX

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

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

创建模板Includes/ArticleList.ss

 
<% loop $PaginatedReleases %> $ArticleDate.format("F j, Y"), $H1
<% end_loop %> <% if $PaginatedReleases.MoreThanOnePage %> <% if $PaginatedReleases.NotFirstPage %> <% end_if %> <% loop $PaginatedReleases.Pages %> <% if $CurrentBool %> $PageNum <% else %> <% if https://stackoverflow.com/questions/37685842/silverstripe-create-pagination-based-on-dropdown-selection/$Link %> <% else %> ... <% end_if %> <% end_if %> <% end_loop %> <% if $PaginatedReleases.NotLastPage %> <% end_if %> <% end_if %>

然后可以将您的页面模板拆分为:

 $YearFilterForm <% include ArticleList %> 

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

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

由于这会影响对yearindex (未过滤条目)的调用,因此在控制器中创建一个helper方法,如下所示:

 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模板。

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