jquery: Tabulator 出来てみた5(AJAX Data Loading)

色々ネタを詰め込もうかとも思ったんだけど、これだけでソコソコなので独立したネタとして。

jquery: Tabulator 出来てみた5(AJAX Data Loading)

前置き(1)

ここまではデータは全て自 html に埋め込んでたが、なぜデータを分離しなかったかと言えば、そりゃ「Wordpress なアタシのブログ」範疇外のデータを管理するのが相当煩わしい、てのがあったから。正式なちゃんとした道具を作るんならそうでもするけれど、今やってるみたいな「Tabulator お試し」のたんびにデータをアップロードするのはたまらんし、と。

それだけじゃなくて、「お試し」でデータを分離してしまうと、「非同期」が付きまとうのでね、「Tabulator の基礎」を学ぶのには相応しくないのよ。

前置き(2)

「AJAX Data Loading」という「機能」が Tablator に内蔵されているとしてもしてないとしても、「AJAX Data Loading」自体は jquery を使って書くことはそう難しくはないことに注意

というよりは、あとでわかるが、一つ前でも触れた「This functionality is only available for nested objects and will not work with arrays.」のことがあるので、「なんだよ、Tabulator に都合のいい json じゃなかったらもうアウトじゃん」てことがわかってしまえば、Tablator に内蔵されているソレを使るケースはかなり少ないことはわかるはず。

ネタ探し

自分で作らずにダイレクトに json を返してくれるようなサービスはないかなぁ、と探したら、凄まじく便利な「ポータル」を発見:

で、MetaWeather。使い方は滅茶苦茶簡単で、locationsearch で問い合わせたい位置(Tokyo、等)の woeid を調べたら、あとは https://www.metaweather.com/api/location/1118370/ (東京の本日から数日間予報らしい)とか、https://www.metaweather.com/api/location/1118370/2018/1/4/ (東京の 2018/1/4 までの実況データ、かしら?) とか。

てみた

https://www.metaweather.com/api/location/1118370/ が「Tabulator に都合のいい json」でないことはわかる? ので、https://www.metaweather.com/api/location/1118370/2018/1/4/ の方で。

まずは「失敗作」:

これが失敗するのは chrome だけっぽい情報も見かけたが、要するにいつもの「クロスドメイン問題」である。こんなもんはプロキシー通しちまえ:


てわけで

https://www.metaweather.com/api/location/1118370/ がダメなのはわかるでしょう? Fields In Nested Data の範疇ではどうにもならない。それに何かの API が都合よく json で返してくれるとは限らなくて、まぁ「読みやすい(くて扱いにくい)html」か「ヘビー級な xml」が主流だもの、なのでそんなに Tablator に内蔵されているヤツを使える機会は多くないはず。無論データをサービスする部分も自分でコントロール出来るなら活用すればいいと思うけれど。

なので結局データローダは自分で書くことが多いだろうし、たぶんその方が遥かに柔軟なのではないかと思う。こっちならサービスが XML を返してきたとしても読み替え出来るであろうし。

15:30 追記: 節穴。ajaxResponse

ちゃんと読めば Set data using AJAX の少し下にちゃんと Ajax Response Alteration なんてのが書いてあった…。

なので https://www.metaweather.com/api/location/1118370/ でも出来る:


ただ…、そうなんだけど「結局データローダは自分で書くことが多いだろう」は相変わらずだと思うよ。たとえば https://www.metaweather.com/api/location/1118370/ だと consolidated_weather の外に結構色んな情報が入ってるでしょう? 何が主役かにもよるけれど、このデータ全体を活用したいという際に、無理やり Tabulator の ajaxResponse を入り口にする必要はないと思う。(つまりテーブルに突っ込む表データとそうでない情報を別々の UI に一度に流し込みたい、なんて良くあるでしょうよ。)

2018-01-05追記

ここでやった MetaWeather の例を「道具」として整理してみた:

ちょっとだけこれまでやってこなかった機能も使ってるけど、まぁ読めばわかるよね?

2018-01-05さらに追記

うーん。ワタシは基本 Chrome しか使わないので「個人的には」困らないんだけれど、試しに Windows 7 標準の IE11 でやってみたら…。「Ajax Load Error – Connection Error: 400 Header required」。FireFox でも問題なく読めるんで、IE だけなのよね。

Tabulator の問題なのかなんなのか、何の原因特定も出来てない。多分そうするには Tabulator の AJAX Data Loading 「機能」を使わずに自力でやってみて振る舞いの違いをみるとかしないとわからん気がするね。当座自分では原因究明しようとは思わないけれど、「お仕事モード」で利用したい人は注意してね。

2018-01-10 追記: realod, refresh

進化した:

「道具」の機能的にはリロード出来るようにした、単位変換できるようにした、の2点で、「Tabulator お試し」ネタとしては、Repeated RequestsRedrawing the table

いつものように「フレームのソースを表示」でみてもらえればだいたいわかるとは思うが一応:

  1 <html>
  2 <head jang="ja">
  3 <meta charset="UTF-8">
  4 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tabulator/3.3.2/css/tabulator_site.min.css">
  5 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  6 <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  7 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/tabulator/3.3.2/js/tabulator.min.js"></script>
  8 </head>
  9 <body>
 10 Temperature:
 11 <select class="select_units" id="temp_unit">
 12   <option value="*:1.0" selected>Celsius</option>
 13   <option value="*:1.8,+:32.0">Fahrenheit</option>
 14   <option value="+:273.15">Kelvin</option>
 15 </select>
 16 Pressure:
 17 <select class="select_units" id="pressure_unit">
 18   <option value="*:1.0" selected>hPa</option>
 19   <option value="*:100">Pa</option>
 20   <option value="*:0.75006375541921">mmHg</option>
 21 </select>
 22 Speed:
 23 <select class="select_units" id="speed_unit">
 24   <option value="*:1.0">mph</option>
 25   <option value="*:0.868976">kts</option>
 26   <option value="*:0.44704" selected>m/s</option>
 27   <option value="*:1.60934">km/h</option>
 28 </select>
 29 Visibility:
 30 <select class="select_units" id="visibility_unit">
 31   <option value="*:1.0">Miles</option>
 32   <option value="*:1.60934" selected>km</option>
 33   <option value="*:0.868976">NM</option>
 34 </select>
 35 <div id="weather-table"></div>
 36 <input type="button" id="reload" value="Reload"/><br/>
 37 
 38 <script>
 39 function floatFormat(cell, formatterParams) {
 40     var v = cell.getValue();
 41     if (v !== null) {
 42         // get unit conversion formurala
 43         var f = cell.getField();
 44         var ftype = f.split("_")[1] || f;
 45         var coefs = $("#" + ftype + "_unit").val(); // "*:1.8,+32.0", etc.
 46         if (coefs) {
 47           coefs = coefs.split(","); // "*:1.8", etc.
 48           coefs.forEach(function (c, i) {
 49               var opef = c.split(":"); // ["*", "1.8"], etc.
 50               console.log(opef);
 51               if (opef[0] == "*") {
 52                 v *= parseFloat(opef[1]);
 53               } else if (opef[0] == "+") {
 54                 v += parseFloat(opef[1]);
 55               }
 56               console.log(v);
 57             });
 58         }
 59         return v.toFixed(1);
 60     }
 61     return "";
 62 }
 63 function stateFormat(cell, formatterParams) {
 64     var v = cell.getValue();
 65     return "<img width='32pt' src='https://www.metaweather.com/static/img/weather/" + v + ".svg'/>";
 66 }
 67 $("#weather-table").tabulator({
 68     "layout": "fitDataFill",
 69     "footerElement": "Powered by <a href='https://www.metaweather.com/' target=_blank>MetaWeather<sub>beta</sub></a>. " + "If you want to know the meaning of each value, see <a href='https://www.metaweather.com/api/' target=_blank>API</a>.",
 70     "variableHeight": true,
 71     ajaxResponse:function(url, params, response) {
 72         // url - the URL of the request
 73         // params - the parameters passed with the request
 74         // response - the JSON object returned in the body of the response.
 75 
 76         return response.consolidated_weather; //return the tableData peroperty of a response json object
 77     },
 78     "columns": [
 79         {
 80             "field": "applicable_date",
 81             "title": "applicable date",
 82             "frozen": true,
 83         },
 84         {
 85             "align": "center", "formatter": stateFormat,
 86             "field": "weather_state_abbr",
 87             "title": "weather state",
 88             "frozen": true,
 89         },
 90         {
 91             "title": "temperature",
 92             "columns": [
 93                 {
 94                     "align": "right", "formatter": floatFormat,
 95                     "field": "min_temp",
 96                     "title": "min"
 97                 },
 98                 {
 99                     "align": "right", "formatter": floatFormat,
100                     "field": "the_temp",
101                     "title": "avg"
102                 },
103                 {
104                     "align": "right", "formatter": floatFormat,
105                     "field": "max_temp",
106                     "title": "max"
107                 }
108             ]
109         },
110         {
111             "align": "right", "formatter": floatFormat,
112             "title": "pressure",
113             "field": "air_pressure",
114         },
115         {
116             "title": "wind",
117             "columns": [
118                 {
119                     "align": "right", "formatter": floatFormat,
120                     "field": "wind_speed",
121                     "title": "speed"
122                 },
123                 {
124                     "title": "direction",
125                     "columns": [
126                         {
127                             "field": "wind_direction_compass"
128                         },
129                         {
130                             "align": "right", "formatter": floatFormat,
131                             "field": "wind_direction"
132                         }
133                     ]
134                 }
135             ]
136         },
137         {
138             "title": "humidity",
139             "field": "humidity",
140             "formatter": "progress"
141         },
142         {
143             "align": "right", "formatter": floatFormat,
144             "title": "visibility",
145             "field": "visibility"
146         },
147         {
148             "title": "predictability",
149             "field": "predictability",
150             "formatter": "progress"
151         }
152     ],
153     "tooltips": true,
154     "tooltipsHeader": true
155 });
156 $("#weather-table").tabulator("setData", "https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/1118370/");
157 $(".select_units").on("change", function() {
158     $("#weather-table").tabulator(
159       "redraw",
160        true /* trigger full rerender including all data and rows */
161     );
162 });
163 $("#reload").on("click", function() {
164     // You can call the setData function to refresh the data at any point
165     $("#weather-table").tabulator("setData");
166 });
167 </script>
168 </body>
169 </html>

options の value に変換式の仕様を独自のというかヘンチクリンな形式でパックしちゃってるんでそこだけ読みにくいかもしれんけど、それ以外はわかるよねすぐに。それと…、真似して何か作りたいなら console.log は消せよ。(あと formurala は手が滑っただけなので、生暖かい目で見やがれ。)



Related Posts