開発メモ,主に補足by子連れ親父プログラマー
2010-10-21
2010-10-01
テーブルの一番右端の列の値だけを取り出したい
ラベル:
jQuery
テーブルの一番右端の列の値だけを取り出したい
テーブルの一番右端の列に文字が入っていて、中にはリンクが貼られている場合もあるとする。
リンクが貼られている場合はそのURLを、文字だけの場合は、文字を、取り出したい。
こんな感じにしてみた。
リンクが貼られている場合はそのURLを、文字だけの場合は、文字を、取り出したい。
var val='';
$('tr td:last-child').each(function(n){
if ($(this).find('a').attr('href') != '') {
val += $(this).find('a').attr('href')+"\n";
} else {
val += $(this).text()+"\n";
}
});
$('body').append('' + val + '');
こんな感じにしてみた。
2010-09-15
jQuery で table をいじるときは tbody を忘れない
まぁ普通に会員の一覧検索みたいな管理画面を作っていて、普通に table でタグが組んであって、それを項目名をクリックしたらその項目名の昇順で並び替えたいとか、そんなような作業ってのは結構あるわけで。
なんかこう、テーブルのそのデータ行の部分だけを Ajax で load するようにしたいなと。
思ったわけです。
で、テーブルは普通に、こんな感じであって、
テーブルの2行目以降を一旦 remove() とかで消して、そこに append() すりゃいいんじゃないかとか、いろいろ悩んでみたんだけど、結局、tbodyを使うってことで解決しました。
先のテーブルを以下のように書き直します。
result.php にはページ中のフォームの値がGETで渡っていくので、それを適当に処理してクエリーをかけて結果を元に
なんかこう、テーブルのそのデータ行の部分だけを Ajax で load するようにしたいなと。
思ったわけです。
で、テーブルは普通に、こんな感じであって、
<table id="result">
<tr>
<th>ID</th>
<th>氏名</th>
<th>メールアドレス</th>
</tr>
<tr>
<td>1</td>
<td>山田</td>
<td>yamada@・・・.jp</td>
</tr>
<tr>
<td>2</td>
<td>佐藤</td>
<td>sato@・・・.jp</td>
</tr>
</table>
このデータ行の部分だけを Ajax で書き換えたいってことなんですが、どうすればいいですかね?テーブルの2行目以降を一旦 remove() とかで消して、そこに append() すりゃいいんじゃないかとか、いろいろ悩んでみたんだけど、結局、tbodyを使うってことで解決しました。
先のテーブルを以下のように書き直します。
<table id="result">
<thead>
<tr>
<th>ID</th>
<th>氏名</th>
<th>メールアドレス</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>山田</td>
<td>yamada@・・・.jp</td>
</tr>
<tr>
<td>2</td>
<td>佐藤</td>
<td>sato@・・・.jp</td>
</tr>
</tbody>
</table>
そして、
$(document).ready(function() {
$('#result tbody').load(
'./result.php',
$('form').serialize(),
function(data){}
);
});
と jQuery で書きます。result.php にはページ中のフォームの値がGETで渡っていくので、それを適当に処理してクエリーをかけて結果を元に
<tr>
<td>1</td>
<td>山田</td>
<td>yamada@・・・.jp</td>
</tr>
<tr>
<td>2</td>
<td>佐藤</td>
<td>sato@・・・.jp</td>
</tr>
の部分だけを出力してやればよいです。
2010-09-11
jQuery、Form Plugin を使って、file upload する、ファイルを選択したら自動でその画像が表示されるようにする
まあ、とにかくファイルアップロード系のプラグインってのはあるようでないようで、これというのがない。
もう探し疲れたよ、ほんとに。
ファイルのアップロードのインターフェースはこういうのがいいんだ、っていう部分で人によって意見が違いすぎるんだよな、結局。
だから作者によって考えてることが全然別々で。
ということで、一番シンプルで、機能がなくて、ただアップロードできるだけ、というものを考えてみた。
まず、HTML側はこうする。
まず、
http://www.malsup.com/jquery/form/
こちらから Form Plugin を入手して、読み込む。
json にすると動かないので注意。
ajaxSubmit で form の action 先を upload.php に変更して、自動でサブミットしてくれる。
ということなので upload.php を書く。
いや、これはまあ、普通に $_FILES を使ったファイルアップロード処理を php で書けばいいだけなので詳細は略。
普段自分が使ってるやつでやってくれ。
なんやかんや処理した後に、
で、アップロードに成功すると
ので、jQuery の .attr を使って画像のパスを書き換える。
あとは好きなようにいじればよしと。
もう探し疲れたよ、ほんとに。
ファイルのアップロードのインターフェースはこういうのがいいんだ、っていう部分で人によって意見が違いすぎるんだよな、結局。
だから作者によって考えてることが全然別々で。
ということで、一番シンプルで、機能がなくて、ただアップロードできるだけ、というものを考えてみた。
まず、HTML側はこうする。
<form id="upload" method="post" action="form.php" > <input type="file" name="sample" id="sample" /> <img id="sample_img" src="img/sample.jpg"> </form>sample.jpg はデフォルトの画像で用意してあって、最初から表示されているんだけど、ファイル参照で別の画像を選べばそれに置き換わる、というようなものを作ろうってことだ。
まず、
http://www.malsup.com/jquery/form/
こちらから Form Plugin を入手して、読み込む。
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="js/jquery.form.js"></script>で、ファイル選択したらファイルアップロードをする php に処理を渡せばいいので、
$(document).ready(function() {
$("input#sample").change(function(){
var options = {
url: 'upload.php',
dataType: 'xml',
success: processXml
};
$('form#upload').ajaxSubmit(options);
});
});
こんな感じに書く。中味は全部 form プラグインの記述。dataType で xml を選ぶのが味噌だ。json にすると動かないので注意。
ajaxSubmit で form の action 先を upload.php に変更して、自動でサブミットしてくれる。
ということなので upload.php を書く。
いや、これはまあ、普通に $_FILES を使ったファイルアップロード処理を php で書けばいいだけなので詳細は略。
普段自分が使ってるやつでやってくれ。
なんやかんや処理した後に、
header('Content-type: text/xml');
echo <<<END
<root>
<status>$status</status>
<file_path>$file_path</file_path>
<emes>$emes</emes>
</root>
END;
というように xml で結果を返す。上記では $status に成功したかどうか、$file_path にアップロードした画像を保存したファイルのパス、$emes にエラーメッセージ、を格納しているつもりである。で、アップロードに成功すると
success: processXmlとあるように、processXml に処理が渡るので、processXml をごりごり書く。
function processXml(responseXML) {
var status = $('status', responseXML).text();
if (status == 'success') {
var file_path = $('file_path', responseXML).text();
$('#sample_img').attr('src', file_path);
} else {
var emes = $('emes', responseXML).text();
alert(emes);
}
}
xml のデータは
$('status', responseXML).text()
というような書き方で取得できる。ので、jQuery の .attr を使って画像のパスを書き換える。
$('#sample_img').attr('src', file_path);
これでオッケーだ。あとは好きなようにいじればよしと。
2010-08-31
jQueryでFCKEditorのvalueを取り出す
$.ajaxとかでpostしてたらFCKEditor部分の値が渡ってなかったので仕方なく。
めちゃめちゃじゃないですか!
$('iframe').contents().find('td#xEditingArea iframe').contents().find('body').html();
めちゃめちゃじゃないですか!
2010-08-12
window.openとかlocationとかsubmitとか、普通の昔から使ってたJavascriptをjQueryで書く
ラベル:
Javascript,
jQuery
まあ、昔はみんな button に onclick つけたり、画像にjavascriptのリンク貼ったり、
して「戻る」ボタンにてた訳で。
大体もうデザイナーさんから上がってきた時点で、
jQuery とか使い始めるとこういうソースがどうにも耐えられない。
html ソースの中に Javascript のコードが書いてあるのが許せない状態になってしまう。
ということで、これまではよく見かけたコードを書き換えるにはどうしたらいいか調べてみた。
まずはボタンクリックで特定のURLにリダイレクトさせるやつ。
こんなボタンがあるとして、
こんなフォームがあるとして、
こんなんなってて、
ついでにpostじゃなくてgetにしたい、っていう場合、
こうなる。
して「戻る」ボタンにてた訳で。
大体もうデザイナーさんから上がってきた時点で、
<a href="javascript:history.back()"><img src="images/B.gif" width="170" height="36" alt="戻る" /></a>こんなんになってたんだけども。
jQuery とか使い始めるとこういうソースがどうにも耐えられない。
html ソースの中に Javascript のコードが書いてあるのが許せない状態になってしまう。
ということで、これまではよく見かけたコードを書き換えるにはどうしたらいいか調べてみた。
まずはボタンクリックで特定のURLにリダイレクトさせるやつ。
こんなボタンがあるとして、
<input type="button" name="back" value="back" />こんな感じっすか。
$(':button[name=back]').click(function() {
window.location = 'index.php';
});
次、ボタンクリックで window.open サイズ指定も付けて。
$(':button[name=back]').click(function(e) {
window.open('index.html','_blank',
'width=360, height=500, menubar=no, toolbar=no, scrollbars=no');
e.preventDefault();
return false;
});
最後、ただ単にサブミットする。ついでに hidden の値を Javascript で指定。こんなフォームがあるとして、
<form action="index.php" method="post"> <input type="hidden" name="key" value="" /> <input type="submit" /> </form>こんな感じで。
$(':submit').click(function() {
$(':hidden[name=key]').val('123');
$('form').submit();
});
あと、追記だけども、HTML側で指定したフォームの飛び先(action)とは全然別のアドレスに飛ばしたい時もあるよね。こんなんなってて、
<form action="index.php" method="post"> <input type="button" id="preview" value="preview" /> <input type="submit" /> </form>プレビューボタンを押したら、preview.phpに飛ばしたい、っていう場合、
ついでにpostじゃなくてgetにしたい、っていう場合、
こうなる。
$(':button#preview').click(function() {
$('form').attr('action', 'preview.php');
$('form').attr('method', 'get');
$('form').submit();
});
2010-08-11
phpとMySQLで、住所から郵便番号を検索する(逆引き)
大昔に会社のホームページ用に用意した原稿だけど、このまま埋もれてるのも何なのでこちらに載せておきます。
今回は、リアルな住所から郵便番号を検索するプログラムについて考えてみることにします。
例えば「札幌市清田区美しが丘一条N丁目M-1」というような、都道府県の部分だけを除いてあとは全部ひとつつながりの住所があるとする。
これがまあ、15万件くらいですかね、それくらいの件数の住所データを渡されて、「これの郵便番号を出せ」と、そういう指令が出たとする訳です。
さあどうしようかと。
話を簡単にするために、その住所データは以下のようなMySQLデータベースのテーブルに入っているとします。
で、まず考えるのは
日本郵便 http://www.post.japanpost.jp/zipcode/index.html
のページへ行って、郵便番号のデータをもらってくることです。ここに「郵便番号データのダウンロード」というリンクがありますのでクリックして、「全国一括」というやつをダウンロードします。
問題はその中味なのですが、詳しくは
郵便番号データの説明 http://www.post.japanpost.jp/zipcode/dl/readme.html
を読んでもらうことにして、この中で使えそうなのは8番目の市区町村名と9番目の町域名、そしてももちろん3番目の郵便番号(7桁)になりそうです。
その3つだけをインポートしてもよいのですが、それも面倒なので、せっかくのCSV形式のファイルですからそのままMySQLのLOAD DATAを使って一気に入れることにします。
最初に、以下のようなテーブルを作っておきます。
これ一発で郵便番号データがzipsテーブルに入ります。
以上でデータは揃いましたので、usersテーブルの
zipsの方は市区町村名と町域名が別々のカラムになっていますので、 CONCAT を使って合体させて処理します。
一方リアルの住所には番地とか何丁目とかいうのが最後の方についていますので、それをどんどん削除していって、それが、 CONCAT で合体した市区町村名と町域名にマッチしたらその時の郵便番号を取得すればよい、という訳です。
文字を後ろから削除するには LEFT を使います。
ということで、まずは対象となる住所データとその文字列長さを users テーブルから取得します。
そして forループの中に以下の照合処理を入れます。
で、これでテストしてみるとすぐに分かりますが、処理が大変に遅いです。私の試算では15万件のデータを処理するのに、18時間かかると出ました(笑)。
これはおそらく CONCAT でカラムを合体させてるのが原因でしょう。
ということで、市区町村名と町域名をバラバラにしておく意味はないので、カラムとして合体させます。
ついでにインデックスも追加しておきます。
SQLの CHAR_LENGTH もめためたに遅いのでPHP側での処理に変更します。
実行してみましょう。私の環境では15万件の住所の照合は、2分で終わりました。
問題はこの方法でやった郵便番号が本当に全部合っているのか、ということですが、全体の約14%は郵便番号を照合することができません。
リアルの住所自体には大字(おおあざ)などの表記のゆれがあるのと、それと、この方法では町域が「以下に掲載がない場合」の判別ができないからです。
照合できなかった住所でGoogle郵便番号検索をしてみましょう。
これはちゃんとヒットしますが、
今回は、リアルな住所から郵便番号を検索するプログラムについて考えてみることにします。
例えば「札幌市清田区美しが丘一条N丁目M-1」というような、都道府県の部分だけを除いてあとは全部ひとつつながりの住所があるとする。
これがまあ、15万件くらいですかね、それくらいの件数の住所データを渡されて、「これの郵便番号を出せ」と、そういう指令が出たとする訳です。
さあどうしようかと。
話を簡単にするために、その住所データは以下のようなMySQLデータベースのテーブルに入っているとします。
CREATE TABLE users (
id int(11) NOT NULL auto_increment,
name varchar(100),
address varchar(255),
zip varchar(7),
PRIMARY KEY (id)
)DEFAULT CHARSET=utf8;
住所はaddressのカラムで、郵便番号はzipですが、今はzipには何も入っていません。で、まず考えるのは
日本郵便 http://www.post.japanpost.jp/zipcode/index.html
のページへ行って、郵便番号のデータをもらってくることです。ここに「郵便番号データのダウンロード」というリンクがありますのでクリックして、「全国一括」というやつをダウンロードします。
問題はその中味なのですが、詳しくは
郵便番号データの説明 http://www.post.japanpost.jp/zipcode/dl/readme.html
を読んでもらうことにして、この中で使えそうなのは8番目の市区町村名と9番目の町域名、そしてももちろん3番目の郵便番号(7桁)になりそうです。
その3つだけをインポートしてもよいのですが、それも面倒なので、せっかくのCSV形式のファイルですからそのままMySQLのLOAD DATAを使って一気に入れることにします。
最初に、以下のようなテーブルを作っておきます。
CREATE TABLE zips (
zkd_code VARCHAR(255),
kyu_zip VARCHAR(255),
zip VARCHAR(255),
ken_yomi VARCHAR(255),
siku_yomi VARCHAR(255),
cyou_yomi VARCHAR(255),
ken VARCHAR(255),
siku VARCHAR(255),
cyou VARCHAR(255),
fg_a INT,
fg_b INT,
fg_c INT,
fg_d INT,
fg_e INT,
fg_f INT
);
次に、上記日本郵便のサイトでダウンロードした郵便番号データを適当なファイル名で(ここではyubin.csv)、サーバーに保存して、MySQLのコンソール画面から、mysql> LOAD DATA LOCAL INFILE "/home/myhome/yubin.csv" INTO TABLE zips FIELDS TERMINATED BY ',' ENCLOSED BY '"';と、やります。
これ一発で郵便番号データがzipsテーブルに入ります。
以上でデータは揃いましたので、usersテーブルの
+-------+--------------------------------------------------+ | id | address | +-------+--------------------------------------------------+ | 1 | 札幌市清田区美しが丘一条N丁目M-1 | +-------+--------------------------------------------------+というデータと、zipsテーブルの
+---------+--------------------+--------------------+ | zip | siku | cyou | +---------+--------------------+--------------------+ | 0040811 | 札幌市清田区 | 美しが丘一条 | | 0040813 | 札幌市清田区 | 美しが丘三条 | | 0040812 | 札幌市清田区 | 美しが丘二条 | | 0040815 | 札幌市清田区 | 美しが丘五条 | | 0040814 | 札幌市清田区 | 美しが丘四条 | +---------+--------------------+--------------------+というようなデータを見比べて、郵便番号を照合するプログラムを組めばよいわけです。
zipsの方は市区町村名と町域名が別々のカラムになっていますので、 CONCAT を使って合体させて処理します。
一方リアルの住所には番地とか何丁目とかいうのが最後の方についていますので、それをどんどん削除していって、それが、 CONCAT で合体した市区町村名と町域名にマッチしたらその時の郵便番号を取得すればよい、という訳です。
文字を後ろから削除するには LEFT を使います。
SELECT
zip, siku, cyou
FROM
zips
WHERE
CONCAT(siku, cyou) = LEFT('札幌市清田区美しが丘一条N丁目M-1', 10)
このクエリーはヒットしませんが、 LEFT の最後の数字を1ずつ増やして消していけば、いつかはヒットするはずです。ということで、まずは対象となる住所データとその文字列長さを users テーブルから取得します。
$query = "SELECT address, CHAR_LENGTH(address) as len FROM users";
$result = mysql_query($query);
if ($result) {
$n = mysql_num_rows($result);
if ($n){
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
for($i=$row['len'];$i>0;$i--){
// ここに郵便番号テーブルとの照合を入れる
}
}
}
}
forループを使って、最初に数えた文字列長さから始めて1文字すつ削っていこうという作戦です。そして forループの中に以下の照合処理を入れます。
$query2 = "SELECT zip FROM zips WHERE CONCAT(siku, cyou) = LEFT('$address', $i)";
$result2 = mysql_query($query2);
if ($result2) {
$n2 = mysql_num_rows($result2);
if ($n2){
while ($row2 = mysql_fetch_array($result2, MYSQL_ASSOC)) {
echo $row2['zip'] . "\t";
}
break;
}
}
breakを使って、マッチした時点で forループを抜けます。で、これでテストしてみるとすぐに分かりますが、処理が大変に遅いです。私の試算では15万件のデータを処理するのに、18時間かかると出ました(笑)。
これはおそらく CONCAT でカラムを合体させてるのが原因でしょう。
ということで、市区町村名と町域名をバラバラにしておく意味はないので、カラムとして合体させます。
ALTER TABLE zips ADD COLUMN sikucyou VARCHAR(52); UPDATE zips SET sikucyou=CONCAT(siku, cyou);最初に新しいカラムを追加して、UPDATE をかけています。
ついでにインデックスも追加しておきます。
ALTER TABLE zips ADD INDEX (sikucyou);PHPソース内のSQLの方も修正します。
SQLの CHAR_LENGTH もめためたに遅いのでPHP側での処理に変更します。
$query = "SELECT id, address FROM users";
$result = mysql_query($query);
if ($result) {
$n = mysql_num_rows($result);
if ($n){
while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
$address = mysql_real_escape_string($row['address']);
$len = mb_strlen($row['address']);
$zip = '';
for($i=$len;$i>0;$i--){
$query2 = "SELECT zip FROM zips WHERE sikucyou = LEFT('$address', $i)";
$result2 = mysql_query($query2);
if ($result2) {
$n2 = mysql_num_rows($result2);
if ($n2){
while ($row2 = mysql_fetch_array($result2, MYSQL_ASSOC)) {
$zip = $row2['zip'];
}
break;
}
}
}
$query3 = "UPDATE users SET zip='$zip' where id='{$row['id']}'";
$result3 = mysql_query($query3);
}
}
}
実行してみましょう。私の環境では15万件の住所の照合は、2分で終わりました。
問題はこの方法でやった郵便番号が本当に全部合っているのか、ということですが、全体の約14%は郵便番号を照合することができません。
リアルの住所自体には大字(おおあざ)などの表記のゆれがあるのと、それと、この方法では町域が「以下に掲載がない場合」の判別ができないからです。
照合できなかった住所でGoogle郵便番号検索をしてみましょう。
これはちゃんとヒットしますが、
郵便番号 渋谷区桜丘町これはヒットしません。
郵便番号 千代田区丸の内Google先生でも無理なんです。
2010-08-07
GROUP BYを使った表の数値の合計あって、その合計が10個以上とかいう条件で抽出したい時にHAVING句を使う
例えばメンバーIDがあって、それに紐付いたポイント数が複数保存してあるようなテーブルがあるとする。
もしかしてこんなのあり?
ということで、HAVING句を使って、
結果。
member_id | point
-----------+-------
4 | 2
4 | 2
4 | 3
4 | 3
4 | 3
4 | 1
4 | 3
4 | 2
8 | 2
8 | 0
4 | 1
8 | 3
4 | 6
8 | 0
これをGROUP BY を使って合計を出すと、SELECT member_id,SUM(point) AS sum FROM points GROUP BY member_id;
member_id | sum
-----------+-----
4 | 43
8 | 7
こんな結果になるわけですが、この結果表をさらに、合計が10個以上、とかそういう条件で絞り込みたい訳です。もしかしてこんなのあり?
SELECT member_id, SUM(point) AS sum FROM points WHERE sum > 10 GROUP BY member_id;とかやってみましたが、これは、
ERROR: column "sum" does not existになります。だめです。
ということで、HAVING句を使って、
SELECT member_id, SUM(point) AS sum FROM points GROUP BY member_id HAVING SUM(point) > 10;というように書きます。
結果。
member_id | sum
-----------+-----
4 | 43
Javascriptで配列の後ろからn個だけ要素を削除する
ラベル:
Javascript
だいたいどこのサイトでも要素の削除にはspliceを使え、マイナスにすれば後ろから削除できる、と書いてあるんだが、そのマイナスの意味がよく分からないので実験してみた。
基本的にはこんな風にしておいて、アラートで結果を確認することとしよう。
つまり、一番最後から3個削除したいんだったら、
基本的にはこんな風にしておいて、アラートで結果を確認することとしよう。
items = new Array("1", "2", "3", "4", "5", "6");
items.splice(1, 2);
for(i = 0; i < items.length; i++){
alert(items[i]);
}
これの結果は、
("1", "4", "5", "6")
じゃあこうすると、items.splice(-1, 2);こうなる。
("1", "2", "3", "4", "5")
どうもマイナスにすると、一番最後から数えるってだけのようです。つまり、一番最後から3個削除したいんだったら、
items.splice(-3, 3);こうすればいいと。これを
items.splice(-3);こう書くと、Firefoxやchoromeでは同じく3個削除で動くがIEでは全く削除されない。
登録:
投稿 (Atom)
このブログを検索
人気の投稿
Powered by Blogger.
