Sorry, this entry is only available in 日本語.
Tag Archives: javascript
Use AngularJS on Rails form_for
I used AngularJS on Rails form_for. The most annoying thing is form_for generates form tag with action attribute.
Environment
- Rails 4.1.8
- Ruby 2.2.2
- AngularJS 1.4.7
- Ubuntu 15.04
Circumstance
Rails form_for
generates form tag with some attributes, including action
. Of course, we can add other attributes. But, AngularJS conflicts with this.
In the following code, problem occurs.
1 2 3 4 5 |
<%=form_for(@user, html: {'data-ng-submit': 'mainCtrl.create()', novalidate: :novalidate, name: 'createForm'}) do |f|%> <%=f.label :name%> <%=f.text_field :name, required: :required, 'data-ng-model': 'user.name'%> <button>submit</button> <%end%> |
After clicking the button, AngularJS process will be executed and original form process will be executed.
AngularJS prevent original process when form doesn’t have action attribute, but rails add action attributes automatically. I couldn’t find the way to prevent rails from adding action attribute.
Solution
Add onsubmit="return false;"
to the form tag.
1 2 3 4 5 |
<%=form_for(@user, html: {'data-ng-submit': 'mainCtrl.create()', novalidate: :novalidate, name: 'createForm', onsubmit: "return false;"}) do |f|%> <%=f.label :name%> <%=f.text_field :name, required: :required, 'data-ng-model': 'user.name'%> <button>submit</button> <%end%> |
また AngularJS: How to prevent form submission after click on button? に記載されているような方法もありますが、 javascript として 他のところで使えないので、 上に書いたやり方の方がきれいに見えます。
How to Sort Table in Javascript
javascript を使ってテーブルをソートすることになった。ドットインストールを見ると複数項目でソートする方法まで載っている・・・が、これを一般化してどんなテーブルでもソートできるようにするにはどうするか考えてみた。公開されているライブラリもあるんですけどね。
The code is as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
var sortFunctions = (function() { var weekday_names = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; /** * Comparing Strings * Weekday String is compared in order of the weekday. */ var compareString = function(a, b) { a = a.trim(); b = b.trim(); var a_week_index = weekday_names.indexOf(a); var b_week_index = weekday_names.indexOf(b); if (a_week_index >= 0 && b_week_index >= 0) { a = a_week_index; b = b_week_index; } if (a == b) { return 0; } else { if (a > b) { return 1; } else { return -1; } } } /** * 2 つの tr の順序を与えられた order によって比較する * @a * @b * @order_array [[number, order], ...] order は並び順(昇順なら1), number は td の順次(0 から始まる) * @sort_array */ var compareTr = function(a, b, order_array, sort_array) { var a_tds = $(a).find('td'); var b_tds = $(b).find('td'); for (var i = 0; i < sort_array.length; i++) { value = compareString( a_tds.eq(sort_array[i]).text(), b_tds.eq(sort_array[i]).text()); if (value != 0) { return value * order_array[sort_array[i]]; } } return 0; } /** * Generate Order array * @index 変更対象のカラムのindex * @last_index */ var composeOrder = function(index, order_array, sort_array) { // 最後にソート対象になっていた場合は逆順にソートするように設定する。 if (sort_array.length > 0 && index == sort_array[0]) { order_array[index] *= -1; } else { var remove_index = -1; for (var i = 1; i < sort_array.length; i++) { if (sort_array[i] == index) { remove_index = i; break; } } if (remove_index > 0) { sort_array.splice(remove_index, 1); } sort_array.unshift(index); } } /** * Sort rows */ var sortRows = function(rows, order_array, sort_array) { rows.sort(function(a, b) { return compareTr(a, b, order_array, sort_array); }); return rows; } var AscChar = '▼'; var DescChar = '▲'; /** * テーブル行の並び替え * @target_table 並び替え対象のテーブル * @orders 並び替えの順番 * @sort_orders 並び替えの優先順位 */ var _sort = function(order_array, sort_array, start_object) { var target_table = $(start_object).parent().parent().parent(); var head = target_table.find('thead>tr>th'); var rows = target_table.find('tbody>tr'); var index = $(head).index(start_object); if (sort_array.length > 0) { var text = $(head).eq(sort_array[0]).text(); if (order_array[sort_array[0]] > 0) { text = text.replace(AscChar, ''); } else { text = text.replace(DescChar, ''); } $(head).eq(sort_array[0]).text(text); } // ソート順序を決定する。 composeOrder(index, order_array, sort_array); // 並び替える。 var new_rows = sortRows(rows, order_array, sort_array); target_table.children('tbody').empty().append(new_rows); var head_text = ""; if (order_array[sort_array[0]] > 0) { head_text += AscChar; } else { head_text += DescChar; } $(head).eq(sort_array[0]).text( head_text + $(head).eq(sort_array[0]).text()); } return {sort: _sort}; })(); |
The preceding code sorts table rows with sortFunction.sort and shows “▼”/”▲”. sort function receives 3 parameters, order_array, sort_array and clicked th tag (this). 各パラメータについて下に説明を書いた。
- order_array
-
Storing each columns’ order directions, ASC/DESC. If you have 4 columns, it have to be like
[1, 1, 1, 1]
. 1 means ascending, -1 means descending. If the table is not sorted in initial state, it’s OK to set 1.ソートをするときに 昇順・降順 が入れ替わる場合は 該当する値を 1 と -1 で入れ替える。 SQL の order by でいうところの ASC, DESC 。
- sort_array
-
This parameter is array that shows which column is used for sorting. If the table is sorted with first and second column, and sorted with first column primarily, then the parameter have to be
[0, 1]
. If the table is not sorted, the parameter have to be[]
.最後にソートされた列の index は 配列の先頭に追加する。 This is like column order in order by clause of SQL.
- this (th)
This enables us to detect which column is clicked.
Issues
- 並べ替えられるオブジェクトに対して $(object).click() のようにしてイベントを記述している場合、並べ替え後に同じことをやる必要がある。
- 列の表示名に ▲(▼) を使用すると、ソートの際に消える。
- ▲(▼) は 最後にソートした列のみに表示する。
- 昇順・降順のときの大小の比較は Sun, Mon, … , Sat が記述されている場合は 日曜を先頭にして考える。文字列は javascript 上 の >, < で比較する。数値の比較には対応していない。
- table の中には 必ず thead, tbody を記述する。 parent() の数が固定で書かれているため。
order の扱いについては、 order by column_name_1 DESC, column_name_2 ASC のように [[0, -1], [1, 1]] で表すことも考えたが、優先順位と降順・昇順を別にしたほうがわかりやすいのではないかと思って上のようになった。
また、ある列で降順でソートされた後に別の列で昇順でソートした場合、最初にソートした降順は保持されるが、今になって降順・昇順は全列で統一したほうがよいのではないかと思っている。
Rails: The Code to show Tooltip
This is the story I tried to show tool tip in Ruby On Rails.
It’s simple. Show help message when it is clicked, and hide message when it is clicked again. はてなマークがクリックされたらツールチップを表示・非表示するということです。
I used javascript (jQuery) and CSS. And I created useful method in helper as follows.
Environment
- Ruby 1.8.7p374
- Rails 3.0.1
- jQuery 1.4.3
Base
1 2 3 4 5 6 7 8 9 10 |
.help-tooltip { max-width: 600px; background-color: #fff; display: none; z-index: 10; font-size: 12px; position: static; border: solid 1px black; padding: 2px; } |
1 2 3 4 5 6 7 |
$('.help-tooltip-trigger').live( 'click', function () { $(this).next().slideToggle('fast'); } ); |
上のように javascript と css を記述して、次のように HTML を書きます。
1 2 3 4 5 6 |
<span class="help-tooltip-trigger"> <img src="image/quotation.png" style="width:16px;height:16px;" /> </span> <div class="help-tooltip"> <p>Help Message</p> </div> |
image/quotation.png はクリックするモノです。その画像をクリックすると表示・非表示が切り替えます。
正確にいうなら、画像を囲んでいる span をクリックすると、その直後のタグの表示・非表示を切り替えます。つまりクリックするものは画像でなくてもよく、もっというならツールチップ以外にも使えるということです。
Use helper
Rails prepares helper component.
1 2 3 4 5 6 7 8 9 |
def help_tooltip(message, size = '16x16') result = content_tag(:span, {:class => 'help-tooltip-trigger'}) do image_tag 'icons/question.png', :size => size end result += content_tag(:div, {:class => 'help-tooltip'}) do raw message end return result end |
このメソッドを次のようにして使うと、上に書いた HTML のように出力されます。
1 |
<%=help_tooltip '<p>Help Message</p>', '16x16'%> |
Second argument has default value, so we don’t have to set any value to it.
私がこの tooltip 表示を書き始めたら ほかの人が随所で真似し始めたので、もっと楽にできる helper のメソッドを作ったというお話でした。
Password Generator
I created password generator where you can create random password.
Continue reading Password Generator