2016-07-01 125 views
1

我有一個文章列表,可以根據年份的下拉列表按年排序。我問了這個問題,並得到了一個驚人的答案,但現在我注意到一個問題:每當用戶點擊「返回」時,文章列表總是重置爲默認視圖(即顯示所有文章)。但是,下拉列表「會記住」用戶所做的選擇。我希望文章列表與下拉菜單中的選擇年份相匹配,以保持用戶的一致性和易用性(我不希望他們必須重新選擇他們每次點擊文章後退按鈕時選擇的年份) 。SilverStripe - 保持下拉選定內容時點擊返回按鈕

我知道我可以使用會話變量,但我不知道這是否真的有必要嗎?或者,也許這是更容易考慮如何設置代碼的路線?

這裏是我對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 

回答

1

我想你會遇到這個問題,因爲表格是從一個狀態開始的這與頁面加載時的默認不同,因此內容(通過JS加載)與表單字段不同步。

一個簡單的 - 儘管有點冒險 - 的方法是隻通過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功能。

+0

這幾乎就是我想要的!但是,有一個問題...我在控制檯中看到這個錯誤:History.getState不是一個函數。該功能在其他方面起作用,但似乎打破了旨在使提交按鈕過時的jQuery。我不明白這是爲什麼。它看起來像一切正確,但.getState()拋出一個錯誤。 –

+0

您是否下載並添加歷史JS腳本?請參閱:https://github.com/browserstate/history.js#download-installation – bummzack

+0

我嘗試了不同的,沒有成功。現在我正在使用未壓縮目錄中的history.js。 https://github.com/browserstate/history.js/tree/master/scripts/uncompressed –

相關問題