MVC 中使用Razor產生 多選的 ListBox

  • 2699
  • 0
  • MVC
  • 2019-06-26

在MVC的專案中,使用Razor語法產生ListBoxFor,提供使用者多選列表內資料

如何正確初始化空白的SelectList。

今天在開發MVC專案的時候,手邊有一個需求

需要產生兩個ListBox,一邊是從DB裡面帶出資料,一邊是讓使用者透過四個功能鍵選取,

紀錄一下如何使用Razor產生兩個ListBox

首先準備ViewMode

public class Condition
{
	/// <summary>
	/// 左邊實際選取的值 
	/// </summary>
	public List<String> LEFT_DEPTID_List { get; set; }

	/// <summary>
	/// 右邊選取的值 
	/// </summary>
	public List<String> RIGHT_DEPTID_List { get; set; }
}

public class ViewData
{
    public Condition condition{get;set;}
	
	/// <summary>
	/// 左邊列表的內容資料(資料來源) 
	/// </summary>
	public SelectList LEFT_DEPTID_SelectList { get; set; }

	/// <summary>
	/// 右邊列表的內容資料(資料來源)
	/// </summary>
	public SelectList RIGHT_DEPTID_SelectList { get; set; }
}

在第一次產生頁面的時候,我需要產生資料來源 ,

這邊要特別注意的是 空白SelectList的正確宣告方式  new SelectList( Enumerable.Empty<SelectListItem>());

public ActionResult DemoEdit()
{
   ViewModel viewModel = new ViewModel();
   //初始化左邊的資料列表
   viewModel.LEFT_DEPTID_SelectList = 左邊要顯示的資料來源(Type:SelectList);

   //右邊要帶入空白,因為使用者還沒選擇,要注意這邊是空白SelectList的正確宣告方式
   viewModel.RIGHT_DEPTID_SelectList = new SelectList( Enumerable.Empty<SelectListItem>());


   viewModel.condition = new Condition();
   viewModel.condition.LEFT_DEPTID_List = new List<string>(); // 單位左邊已經選取的值,NULL,使用者還沒選
   viewModel.condition.RIGHT_DEPTID_List = new List<string>(); // 單位右邊已經選取的值,NULL,使用者還沒選
   
   return View(viewModel);
}

再來就是View的部分,使用Razor語法產生

<div class="form-group">
	<label class="control-label col-md-2" for="selDEPID_OLD" style="display:inline;">單位代號:</label>
	<div class="col-md-8">
		<div style="display:inline-block;vertical-align:top;">
			@Html.ListBoxFor(c => c.condition.LEFT_DEPTID_List, Model.LEFT_DEPTID_SelectList, new { @class = "form-control ", id = "selDEPID_OLD",disabled="disabled", style = "width:220px;height:160px;display:inline;margin-right:10px;" })
		</div>
		<div style="width:30px;height:160px;display:inline-block;vertical-align:top;">
			<span style="cursor:pointer">
				<input type="button" disabled class="btn" style="background-image:url('/Content/Images/arrow_double_right.jpg');width:25px;height:25px;" id="arrow_double_right" />
			</span>
			<br><br>
			<span style="cursor:pointer">
				<input type="button" disabled class="btn" style="background-image:url('/Content/Images/arrow_right.jpg');width:25px;height:25px;" id="arrow_right" />
			</span>
			<br><br>			
			<span style="cursor:pointer">
				<input type="button" disabled class="btn" style="background-image:url('/Content/Images/arrow_left.jpg');width:25px;height:25px;" id="arrow_left" />
			</span>
			<br><br>
			<span style="cursor:pointer">
				<input type="button" disabled class="btn" style="background-image:url('/Content/Images/arrow_double_left.jpg');width:25px;height:25px;" id="arrow_double_left" />
			</span>
		</div>
		<div style="display:inline-block;vertical-align:top;">			
			@Html.ListBoxFor(c => c.condition.RIGHT_DEPTID_List, Model.RIGHT_DEPTID_SelectList, new { @class = "form-control ", disabled = "disabled", id = "selDEPTID_CHOICE", style = "width:220px;height:160px;display:inline;margin-right:10px;" })
		</div>
	</div>
</div>

使用Razor產生的時候,注意

@Html.ListBoxFor(c => c.condition.LEFT_DEPTID_List, Model.LEFT_DEPTID_SelectList,....)

第一個參數是使用者選取的值(List<String>)=>POST到後端的時候就是POST這個資料。

第二個參數是畫面上要顯示的值

[HttpPost]
public ActionResult DemoEdit(ViewModel viewModel)
{
   //這邊就可以看到viewModel.condition裡面兩個List<String>的資料
   // LEFT_DEPTID_List,RIGHT_DEPTID_List
   return View();
}

最後附上Javascript控制動態多選物件的語法

//單位 多選(=>)
function arrow_right_Click() {
    var _selectArray = $('#selDEPID_OLD :selected');
    if (_selectArray.length > 0) {
        $.each(_selectArray, function (inedex, item) {
            $('#selDEPTID_CHOICE').append(item);
        });
    }
}
//單位 多選(<=)
function arrow_left_Click() {
    var _selectArray = $('#selDEPTID_CHOICE :selected');
    if (_selectArray.length > 0) {
        $.each(_selectArray, function (inedex, item) {
            $('#selDEPID_OLD').append(item);
        });
    }
}
//單位 全選 全選(=>>)
function arrow_double_right_Click() {
    var _selectArray = $('#selDEPID_OLD option');
    if (_selectArray.length > 0) {
        $.each(_selectArray, function (inedex, item) {
            $('#selDEPTID_CHOICE').append(item);
        });
    }
}
//單位 全選 (<<=)
function arrow_double_left_Click() {

    var _selectArray = $('#selDEPTID_CHOICE option');
    if (_selectArray.length > 0) {
        $.each(_selectArray, function (inedex, item) {
            $('#selDEPID_OLD').append(item);
        });
    }
}

結論:

1.選取的值會用型態List<String>的方式POST到後端

2.顯示的值用SelectList給值,其實行為模式跟@Razor.DropDownListFor是很類似的

2017/08/03 補充:

測試的時候發現一個問題,已經將左邊的資料選到右邊的ListBox,但是POST到後端的時候,

ModelBinding的值不如預期,看一下下面這張圖

可以發現右邊的ListBix,001 是被selected的,

但是第二個option是沒有被選取,

真正透過Model Binding Post到後段的資料,是有被選取的值才會被POST到後端,

所以如果以目前我的需求(右邊ListBox的值都要儲存)

可以透過JS在存檔前將右邊ListBox的option都設為selected

$($('#selDEPTID_CHOICE option')).prop('selected',true);

這樣就可以正確地將所有右邊ListBox內的值都Post到後端,

當然如果沒有特殊需求,可以沿用現有機制,POST選取的值到後端即可!