[D3] 使用 D3 產生說明文字在後的 Radio Button List

利用 D3 產生 Radio Button List 的小技巧

嚴格來講, D3 並不是操作 DOM 元素的最好工具。使用純 JavaScript 或者其它 framework 都可以把這種事情處理得很好。但是如果一定要使用 D3 來做的話, 以下要講的這個小技巧或許可以幫上小忙。

先講在前面。基本上這篇要介紹的小技巧可以算是個 hack。因為使用基本的語法就「應該」可以把事情做好了。

假設我們要利用 D3 來產一個文字在小圓圈之後的 Radio Button, 我們可能會直覺地這樣寫:

d3.select('#radioSelectTypeHolder')
	.append('input')
	.attr('type', 'Radio')
	.append('label')
	.text('abc')

這樣就會產生如下的 HTML 碼:

<input type="Radio">
	<label>abc</label>
</input>

以上是一個語法上完全沒問題的 XML 碼。但是事實上那個 label 可能是不會出現的; 有些瀏覽器只會 render 出來一個小圓圈 (即 radio button)。最主要的原因, 在於 HTML 中 input 這個標籤是不應該有 end tag 的 (也就是那個 </input>), 所以這一段就不是標準的 HTML 碼。結果這段 HTML 就不一定會正確顯示了。

但如果我們把順序對調一下呢?

d3.select('#radioSelectTypeHolder')
	.append('label')
	.text('abc')
	.append('input')
	.attr('type', 'Radio')

那麼它會產生一個完全 OK 的 HTML 碼, 也可以順利地顯示。

<label>
	abc
	<input type="Radio">
</label>

但問題來了。我們不是說要產生的是一個「說明文字在後」的 Radio Button 嗎? 畢竟我們最終要做出來的 Radio Button List 是如下圖所示的樣子:

文字在右的 Radio Button List

 

 

 

問題就出在瀏覽器並不允許 label 標籤被包在 input 標籤的裡面; 這樣的話, 這個 label 仍舊不會正確地顯示, 有時候它就好像根本不存在一樣。但反過來卻是正確的。

要解決這個問題, 我們就必須採用另一個比較不直覺的方法。也就是先建立一個上層的 DOM 元素, 再分別附加上 input 元素, 再分別附加上 label 元素:

let generationTypeData = ["Number", "Area", "HumanName", "CompanyName", "Address"];

let parentDiv = d3.select('#radioSelectTypeHolder')
   .selectAll('span')
   .data(generationTypeData)
   .enter()
   .append('span');
let radios = parentDiv
  .append('input')
  .attr('name', function(d) { return radioGenerationTypeId; })
  .attr('type', function(d) { return 'Radio'; })
  .attr('value', function(d) { return d; })
  .attr('id', function(d) { return 'radioGenerationType'+d; })
  .property("checked", function(d, i) {return i===0;})
let labels = parentDiv
  .append('label')
  .attr('for', function(d) { return 'radioGenerationType'+d; })
  .text(function(d) {return d;})

換句話說, 我們先建立好一個上層元素 parentDiv, 然後依次產生所有的 Radio Buttons, 再依次產生對應的 Labels。這樣就可以了。

 


Dev 2Share @ 點部落