ajaxでjsonオブジェクトを返す

ajaxjsonオブジェクトを返す処理がなかなかできず苦労したのでメモしておく。

下の処理の最初にハマったポイントは
urlが正しく設定できてない為にGETエラーになるということだ。
ちなみに下のコードでは正しくGETできる。urlが正しく設定できている。
最初はurl:"/tournament/open/" + tournam...(後省略)
とか
url:"" + "/tournament/open/" + tournam...(後省略)
とかやって、エラーが起きてた。

いずれにせよ、urlが正しくないのだ。
どこにいるのか考える。この場合
結論として
相対パスを通すなら、そのいじっているソースコード
どのURLで表示されているのかを考える。
今回の場合、下に書いている部分コードはhome_page.php
というファイルになり、このソースはURLでいうと
http://localhost/index.php/site/goToHome
で表示される。
これに対し、呼び出したいのはtournamentというcontroller
のopenという関数
なので、../tournament/openは
一階層さがってからtournament/openをくっつけるといこで
最終的にはhttp://localhost/index.php/tournament/open
とうパスが生成され、これはURLとして有効なのでGETは成功する。

<script type="text/javascript">
dojo.addOnLoad(function (){
    var tournaments = eval(<?php echo $tournaments_json; ?>);
    
    console.log("tournamets.length: " + tournaments.length);
    for(var key in tournaments){
    	console.log("key : " + key);
    	console.log(tournaments[key].cup + " " + tournaments[key].tournament);
    	var divId = tournaments[key].cup + tournaments[key].tournament;
    	var div = dojo.byId(divId);
    	debugger;
    	dojo.connect(div, "onclick", null, function(context){
        	console.log("base_usl is " + "<?php echo base_url() ?>");
            var baseurl = "<?php echo base_url() ?>";
            console.log("url = " + "../tournament/open/" + tournaments[key].cup + '/' + tournaments[key].tournament);
        	dojo.xhrGet({
            	// たぶんGETではurlで引数を送れない!?
        	    url:"../tournament/open/" + tournaments[key].cup + '/' + tournaments[key].tournament,
        	    handleAs: "text",
        	    content : {
            	    "ajax" : "true"
        	    },
        	    
        	    load: function(data){
            	  console.log("res=", data);
        	      debugger;
        	      var itemdata = data.chart.rows;
        	      var structure = data.chart.columns;
        	      var chart = new dojo.data.ItemFileReadStore( {data :{ items : itemdata }});
        	      var grid = dojox.grid.DataGrid({
            	      id : 'myDataGrid'
                	, store : chart
                	, structure : structure
        	      });
        	      //var grid = dijit.byId("myDataGrid");
        	      
        	    },
        	    error: function(error) {
            	  debugger;
        	      console.warn(new Error().stack);
        	    }
        	});
    	});
    }
});
</script>


さて、この初歩的な問題を乗り越えた次に
私はまだwebProgrammingに慣れてない人であり。今どこ(client側、server側)でソースが実行されてて、サーバーがわのフォルダ階層はどういう仕組で呼び出されていて、とか確実に理解していない。意識して徐々に明確にしていきたい。
GETがうまくいって、すべてうまく行くとおもいきや
そうは行かなかった。
次に、はまった問題は
errorが常によびだされて
Object.errorというエラーを吐き出し続けてくれた。

load functionの先頭にdebugger;停止を挿入しても一行に
error functinoが呼び出される。
ひたすら悩んだ挙句、handleAsを"json"から"test"にしてみたところ、するっとload functionが呼び出された。

つまりは、サーバー側から返されるレスポンスが間違っているのではという懸念ができきた。デバッグをしているとき
これではないだろうかっというアイデアができてきた時はうれしい。

レスポンスのphpでは、ajaxなしで記述していた時のソースをベースにしていて、そのなかでhome_pageをloadして処理を終了しているところとかがあった。
それで僕は、あぁー、ajax通信時にページをloadするような処理はまずいよなぁー、ふむふむ。ってことでphpのfunctinoでは、今回の場合tournament/openで
return json_encode($data);
みたいに直接オブジェクトを返すようにしてみた。

さぁ、どうだ治ったか?
結果はダメ!!

いろいろサンプルをgoogleしてみると
this->load->view("xxx.php");みたいな文はajaxの呼び出されるサーバー側の関数でも
普通に使われている。

あっ、そうなの

じゃあ、やっぱり最初ので良かったんだー。
じゃ、一体なにかまずいんだ。

そんな時こんなページを見つけた。

私が拾ったのはhandleAsを"json"から"text"にしてみる
ということだった。
そしてloadでは単純にresponseの表示(console.logとか)するだけ。

結果、できた!

ということは
レスポンスのjsonオブジェクトがなんかダメなんだ。

htmlのContent-Typeでjsonなんだよ、って明確に宣言して
レスポンスを返す必要があるんだ!

本当は別のサイトで上のことを教えてもらったんだけど、探せなかったからこれで。http://www.ibm.com/developerworks/web/tutorials/wa-dojotoolkit/section3.html


ということで
僕のtournamentコントローラーは以下のようにし、
jsonを明確したviewをloadすることでajax通信が完結しました。

function open(){
		$cup_name = urldecode($this->uri->segment(3));
		$tournament_name = urldecode($this->uri->segment(4));
		
		// get tournament id
		$tournament_id = $this->tournaments_model->getIdByNames(
			$cup_name, $tournament_name
		);
		
		$is_ajax_request = false;
		if(isset($_GET['ajax']) && $_GET['ajax']){
		    $is_ajax_request = true;
		}
		
		if(isset($tournament_id) && $tournament_id != -1){
			
			$data['tournament'] = $this->tournaments_model->getById($tournament_id);
			$data['participants'] = $this->participants_model->getByTournamentId($tournament_id);
			$data['games'] = $this->games_model->getByTournamentId($tournament_id);
			
			$additionalColmns = array(
			    array("name"=>"Additional", "field"=>"win", "width"=>"80px")
			);
			$chart = new Tournament_Group_Chart_Model($tournament_id, $data['participants'], $additionalColmns);
			$data['chart'] = $chart;
			$data['chart_json_file'] = 'tournament_view.json';
            $response['json'] = json_encode($data);
			if($is_ajax_request){
			    if($data['tournament']->tournament_type == "Group"){
			        $this->load->view('tournaments/gruop_tournament_form_json', $response);
			    }else if($data['tournament']->tournament_type == "Knock-out"){
			        $this->load->view('tournaments/gruop_tournament_form_json', $response);
			    }else{
			        $this->load->view('tournaments/gruop_tournament_form_json', $response);
			    }
			}else{
			    $fp = fopen('tournament_view.json', 'w');
			    fwrite($fp, json_encode($data));
			    fclose($fp);
			    	
			    // ajax が有効であればこのページの特定の場所に、そうでなければ新しいページに
			    if($data['tournament']->tournament_type == "Group"){
			        $data['main_content'] = 'tournaments/gruop_tournament_form';
			    }else if($data['tournament']->tournament_type == "Knock-out"){
			        $data['main_content'] = 'tournaments/gruop_tournament_form';
			    }else{
			        redirect("site/goToHome");
			    }
			    $data['title'] = $cup_name . $tournament_name;
			    $this->load->view('includes/template', $data);
			}
			
		}else{
		    if($is_ajax_request){
		        redirect("site/goToHome");
		    }
		}
		
	}

tournaments/gruop_tournament_form_jsonの内容

<?php
$this->output->set_header('Content-Type: application/json; charset=utf-8');
echo $json;
?>