40歳からのキャリアチェンジ

20代はエンジニア・PM、30代はWeb系エンジニア向けのキャリアアドバイザー。40代の今はフリーランスで開発含めて色々やってます。技術ネタとしてはRuby/RailsとJavaScript関連あたり

039-insertRowAfter使った処理がうまくいかずにはまってます

CreateTableViewのreceive()は、エントリ一覧のオブジェクトに加えて、iPhone上で何ページ目が表示されているのかそのページ数を受取、2ページ目以降ならば、TableViewのinsertRowAfterメソッドを使って、rowを動的に追加しようと考えました。

結構簡単にできると思ってやってみたものの、全然できない。。。

現時点で、rowを静的に組み立てて、insertRowAfterに適用しようと思って、こんな感じのコードをCreateTableViewのreceive()内に書きました

       // テストのためにrowを準備して
       var row = Ti.UI.createTableViewRow({
	 hasChild:true,
	 data:entryList,
	 height:80
       });

       var title = Ti.UI.createLabel(styles["titleLabel"]);
       title.text = entryList[0].title,
       row.add(title);
       var content = Ti.UI.createLabel(styles["contentLabel"]);
       content.text = entryList[0].html_body.replace(/<\/?[^>]+>/gi, "");
       row.add(content);
      this.tableView.insertRowAfter(4,row,{});

これで実行すると

[ERROR] invalid number of rows. in -[TiUITableViewProxy insertRowAfter:] (TiUITableViewProxy.m:368)

という感じで怒られます。

もうちょっとでうまくいきそうな予感がしているのですが、その”ちょっと”というのが届きそうで届かないので、めげそうになります

前回のエントリからViewとなるCreateTableViewクラスとModelとなるBloggerクラスを分けはじめまて、今のところ上記のinsertRowAfterの部分がうまくいってないですが、とりあえずソースコード晒します。

//CreateTableView
CreateTableView = function(){
  this.entry_list_length = 5;
  this.list = [];
  this.pagenumber = 1;
  this.win = Ti.UI.currentWindow;
  this.tableView = Ti.UI.createTableView();
  this.pulling = false;
  this.reloading = false;
  this.init();
};
CreateTableView.prototype = {
  init:function(){
    /*
     TableViewのヘッダー部分や、その中のEventListenerは
     初回だけ生成すればOK。
     */
    this.makeTableHeader();
  },
  run:function(entryList){
    var data = [];
    for(var i=0;i<this.entry_list_length;i++){
      var entry =  entryList[i];
      data.push(this.makeView(entry));
    }
    return data;
  },
  receive:function(entryList,current_page){
    /*
     * 最初に読み込まれるページでなければ
     * beginReloadingに結果のエントリ一覧を渡すことで
     * 2ページ目以降のエントリ一覧を生成する
     *
     */

    Titanium.API.info('CURRENT PAGE' + current_page);
    var entries = this.run(entryList);
    if(current_page===1){
      this.pagenumber = current_page;
      this.setData(entries);
    } else {
      this.pagenumber = current_page;
       var row = Ti.UI.createTableViewRow({
	 hasChild:true,
	 data:entryList,
	 height:80
       });

       var title = Ti.UI.createLabel(styles["titleLabel"]);
       title.text = entryList[0].title,
       row.add(title);
       var content = Ti.UI.createLabel(styles["contentLabel"]);
       content.text = entryList[0].html_body.replace(/<\/?[^>]+>/gi, "");
       row.add(content);
      Titanium.API.info(title + ":" + content);
      Titanium.API.info(entryList[1].title);
      this.tableView.insertRowAfter(4,row,{});
    }
  },
  getRow:function(){
    return this.row;
  },
  makeView:function(entry){
    var self = this;
    var row = Ti.UI.createTableViewRow({
      hasChild:true,
      data:entry,
      height:80
    });
    // 記事の詳細情報を表示
    row.addEventListener('click', function(e){
      var title = e.rowData.data.title;
      var html_body = e.rowData.data.html_body;
      var permalink = e.rowData.data.permalink;

      var webView =  Ti.UI.createWebView();
      webView.html = '<html><body>' + html_body + '</body></html>';
      self.win.add(webView);
      Titanium.UI.currentTab.open(self.win,{animated:true});
    });

    var title = Ti.UI.createLabel(styles["titleLabel"]);
    title.text = entry.title,
    row.add(title);
    var content = Ti.UI.createLabel(styles["contentLabel"]);
    content.text = entry.html_body.replace(/<\/?[^>]+>/gi, "");
    row.add(content);
    return row;
  },
  makeTableHeader:function(){
    var self = this;
    var border = Ti.UI.createView(styles["border"]);
    var tableHeader = Ti.UI.createView(styles["tableHeader"]);
    var arrow = Ti.UI.createView(styles["arrow"]);
    var statusLabel = Ti.UI.createLabel(styles["statusLabel"]);
    var lastUpdatedLabel = Ti.UI.createLabel(styles["lastUpdatedLabel"]);
    tableHeader.add(border);
    tableHeader.add(arrow);
    tableHeader.add(statusLabel);
    tableHeader.add(lastUpdatedLabel);

    self.tableView.addEventListener('scroll',function(e){
      var offset = e.contentOffset.y;
      if (offset <= -65.0 && !self.pulling) {
	var t = Titanium.UI.create2DMatrix();
	t = t.rotate(-180);
	self.pulling = true;
	arrow.animate({transform:t,duration:180});
	statusLabel.text = "手を離すと更新";
      } else if (self.pulling && offset > -65.0 && offset < 0) {
	self.pulling = false;
	var t = Titanium.UI.create2DMatrix();
	arrow.animate({transform:t,duration:180});
	statusLabel.text = "Pull down to refresh...";
      }
    });

    self.tableView.addEventListener('scrollEnd',function(e){
      if (self.pulling && !self.reloading && e.contentOffset.y <= -65.0)  {
	self.reloading = true;
	self.pulling = false;
	arrow.hide();
	statusLabel.text = "更新しています...";
	self.tableView.setContentInsets({top:60},{animated:true});
	arrow.transform = Titanium.UI.create2DMatrix();
	self.beginReloading();
      }
    });
    self.tableView.headerPullView = tableHeader;
    return;

  },
  setData:function(data){
    this.tableView.setData(data);
    return this.win.add(this.tableView);
  },
  nextPage:function(){
    this.pagenumber++;
    return this.pagenumber;
  },
  beginReloading:function(){
    /*
     エントリ情報更新する際に、コントローラーに現在のページ数を
     引き渡すことで、コントローラー側で次に何ページを取得すればいいのか
     判定できる
     */
    var self = this;
    var next_page = self.nextPage();

    Titanium.API.info('NEXT PAGE IS ' + next_page);
    setTimeout(function(){
      self.tableView.scrollToTop();
      self.reloading = false;
    },2000);

    var blogger = new Blogger('hibi');
    blogger.getEntry(next_page);
    return;
  }
};

//Blogger
var Blogger = function(blogger){
  this.blogger = blogger;
  this.xhr = Titanium.Network.createHTTPClient();
  this.list = [];
  this.entry_list_length = 5;
  this.objTable = new CreateTableView();
};
Blogger.prototype = {
  getEntry:function(current_page){
    var _url ='';
    var self = this;

    _url =  "http://localhost:4567/api/"
      + this.blogger
      + "/"
      + current_page;

    self.xhr.open('GET',_url);

    self.xhr.onload = function(){
      var entries = JSON.parse(this.responseText);

      //ここでレイアウト情報を生成するようなメソッドを呼び出せばOK?
      self.makeEntryList(entries,current_page);
    };
    self.xhr.send();

  },
  makeEntryList:function(obj,current_page){
    /*エントリ一覧情報となるオブジェクトを生成して
     CreataTableViewのreceiveメソッドを呼び出して
     そちらのクラスでTableViewの生成をする
     */

    for(var i=0;i<this.entry_list_length + 1;i++){
      var entry = obj[i];
      this.list.push(obj[i]);
    }
    return this.objTable.receive(this.list,current_page);

  },
  close:function(){
    this.xhr.onload = null;
    this.xhr = null;
  },
  update:function(){
    var next_url =  "http://localhost:4567/api/"
	+ this.blogger
	+ "/"
	+ this.objTable.nextPage();
    Titanium.API.info(next_url);
    return this.get(next_url);
  }
};