【ionic】タブの中に入れ子でタブをいれる方法メモ - ion-tabs

はじめに

今回やりたかったのはこんな画面。
イマイチできるのか不安だったけど無事できた。

f:id:yoppy0066:20170427004140g:plain:w250

ionicは海外の情報が多くて「ionic tabs inside tabs」とか「ionic tab nested」ってみんな検索してるみたい。

イメージはこんなかんじ
f:id:yoppy0066:20170427004202p:plain

アプリ特有?かわからないけど、タブごとにナビゲーションをつくってタブごとに遷移していくようなイメージ。

実装

app.js

angular.module('ionicApp', ['ionic'])

  .config(function($stateProvider, $urlRouterProvider) {

    $stateProvider

    // ベースとなるタブ
      .state('tabs', {
        url: "/tab",
        abstract: true,
        templateUrl: "templates/tabs.html"
      })

    // ホーム
      .state('tabs.home', {
        url: "/home",
        views: {
          'home-tab': {
            templateUrl: "templates/home.html"
          }
        }
      })

    // ニュースタブの中のタブ
      .state('tabs.news', {
        url: "/news",
        abstract: true,
        views: {
          'news-tab': {
            templateUrl: "templates/news.html"
          }
        }
      })

    // 新着ニュース一覧
      .state('tabs.news.new', {
        url: "/new",
        views: {
          'news-page': {
            templateUrl: "templates/news-new.html"
          }
        }
      })

    // お気に入りニュース一覧
      .state('tabs.news.favorite', {
        url: "/favorite",
        views: {
          'favorite-page': {
            templateUrl: "templates/news-favorite.html"
          }
        }
      })

    // 新着ニュース詳細
      .state('tabs.news.new-detail', {
        url: "/new-detail",
        views: {
          'news-page': {
            templateUrl: "templates/news-detail.html"
          }
        }
      })

    // お気に入りニュース詳細
      .state('tabs.news.favorite-detail', {
        url: "/favorite-detail",
        views: {
          'favorite-page': {
            templateUrl: "templates/news-detail.html"
          }
        }
      })
    ;

    $urlRouterProvider.otherwise("/tab/home");

  });

templates/tabs.html

<ion-tabs class="tabs-icon-top tabs-positive">
  <ion-tab title="ホーム" icon="ion-home" href="#/tab/home">
    <ion-nav-view name="home-tab"></ion-nav-view>
  </ion-tab>
  <ion-tab title="ニュース" icon="ion-document" href="#/tab/news/new">
    <ion-nav-view name="news-tab"></ion-nav-view>
  </ion-tab>
</ion-tabs>

templates/home.html

<ion-view title="ホーム">
  <ion-content class="padding">
    <p>ホーム</p>
  </ion-content>
</ion-view>

templates/news.html

<ion-view title="ニュース">
  <ion-tabs class="tabs-icon-top tabs-positive tabs-top">
    <ion-tab title="新着" href="#/tab/news/new" icon="ion-ios-clock-outline">
      <ion-nav-view name="news-page"></ion-nav-view>
    </ion-tab>
    <ion-tab title="お気に入り" href="#/tab/news/favorite" icon="ion-bookmark">
      <ion-nav-view name="favorite-page"></ion-nav-view>
    </ion-tab>
  </ion-tabs>
</ion-view>

templates/news-new.html

<ion-view title="新着ニュース一覧">
  <ion-content class="padding has-tabs-top">
    <p>新着ニュース一覧</p>
    <a href="#/tab/news/new-detail">詳細へ</a>
  </ion-content>
</ion-view>

templates/news-favorite.html

<ion-view title="お気に入りニュース一覧">
  <ion-content class="padding has-tabs-top">
    <p>お気に入りニュース一覧</p>
    <a href="#/tab/news/favorite-detail">詳細へ</a>
  </ion-content>
</ion-view>

templates/news-detail.html

<ion-view title="ニュース詳細">
  <ion-content class="padding has-tabs-top">
    <p>ニュース詳細</p>
  </ion-content>
</ion-view>

ずらずら書いたけど以上です。

参考
http://codepen.io/Glitchbone/pen/GEcae

【angularjs】$http.postでのjson送信でoptions method not allowedを解決した時のメモ

やりたかったことは、localhostのサーバーで動いてるクライアントHTMLからサーバー上のAPIにPOSTでJSONを送るということでした。
なんかうまくいかなくて色々やってみたけど、結論からいうとangular側は以下のコードでいけました。

クライアント側

$http.post("/path/to/api",{
  param1: "value1",                                                                                                                                                                                                
  param2: "value2"                                                                                                                                                                                                 
});

問題はサーバーサイドにありました。レスポンスヘッダーに以下を追記したらいけました。

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept"

ちなみにfuelphpだと

Input::json(); // array("param1" => "value1", "param2" => "value2");
試したけどうまくいかなかったこと
// REQUEST METHODは解決するがFuelPHPでInput::jsonで取得できない                                                                                                                                                    
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';                                                                                                                         

// REQUEST METHODは解決するがFuelPHPでInput::jsonで取得できない                                                                                                                                                    
$httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;application/json;charset=utf-8';                                                                                          

// REQUEST METHODがOPTIONSとなり、「405 Method Not Allowed」                                                                                                                                                       
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json';                                                                                                                                          

残念ながら丸半日以上でつぶれました。。。以上です

【fuelphp】Redisでロック・排他制御する方法メモ

APIの実装でクライアントからの2重送信対策にRedisを使ってみた。
MySQLでやろうとも思ったのだが負荷のことを考えるとRedisの方がいいのかなという判断。

$token = クライアントから送られるトークン 

$redis = Redis::forge();
if (1 === $redis->setnx($token, 1)) {
  // ロックに成功したら有効期限に1分をセット                                                                                                                                                                 
  $redis->expireAt($token, time() + 60);
} else {
  // ロックに失敗(同じキーが登録済み)なら処理中断                                                                                                                                                                  
}

当初は$redist->get($key)で取得できたら、2重送信と判定していたのだがこれだと全く同タイミングだと正しく判定できない(排他制御できてない)。で、ググてみるとsetnxを使えとのことでした。動作確認したら期待通りの挙動となりました。以上です。

【javascript】iPhoneでpagehideが2回呼ばれたときの対応

今回やりたかったことは、ページから離れるとき(リンクとか)にその内容をサーバーに通知したいということ。pagehideで実装したのだが、なぜかiPhoneだとこれが2回呼ばれる現象だった(safarichromeともに)。

以下のようなコードで確認したところ、2回送信されるのを確認。おそらく全く同時刻にランダム文字列が生成してるためかrandの部分が同じものが送信される。

var flg = true;
window.addEventListener("pagehide", function() {
  if (flg) {
    flg = false;
    var rand = ランダム文字列を生成
    var img = new Image();
    img.src = "https://xxx/?rand=" + rand
    document.body.appendChild(img);
  }
});

なのでやはりサーバー側でちゃんと対応しないとダメだねということで対応しました。以上です。

ionic(corodva)info.plistに追記して日本語化対応する - ios

アプリ内から別アプリを開いたら起動したアプリが全て英語だったのでその対応。というかionicで作ったアプリ自体が日本語化されてなかった。

xcodeでの開発の場合は、info.plistを直接いじればよいけどcorodva使ってる場合はxcode上で直接編集したものはbuild時に戻ってしまうのでcordovaで完結するようにする。

config.xmlへの記述でいけるのかと思ったのだがなぜかうまくいかなかったので別途プラグインを用意してplugin.xmlから追記する形でやってる人がいたのでそのやり方を真似させてもらった。

plugins-dev/plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" id="plugin-localization-ios" version="0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
  <name>Localization Ios</name>
  <platform name="ios">
    <config-file target="*-Info.plist" parent="CFBundleDevelopmentRegion">
      <array>
        <string>Japanese</string>
      </array>
    </config-file>
    <config-file target="*-Info.plist" parent="CFBundleLocalizations">
      <array>
        <string>ja</string>
      </array>
    </config-file>
  </platform>
</plugin>

プラグインをプロジェクトへ組み込む

$ ionic plugin add plugins-dev/

platforms/ios/Sample/SampleCalendar-Info.plist

<key>CFBundleDevelopmentRegion</key>
<array>
 <string>Japanese</string>
</array>                                                                                                                                                                                                           
・・・                                                                                                                                                                                                             
<key>CFBundleLocalizations</key>
<array>
  <string>ja</string>
</array>

info.plistに追記されていればOK。

これで終わろうと思ったらプラグインありました。

https://github.com/enricodeleo/cordova-plugin-ios-localized-strings

$ ionic plugin add cordova-plugin-ios-localized-strings --variable MAIN_LANGUAGE=Japanese --variable ADDITIONAL_LANGUAGES=ja

これだけでいける。けど、指定したパラメータの情報ってどこにも保持されない気がするのでチーム開発だと厳しいのかな。。。以上です

gulp-concatでファイルを新規作成したときに動かなかったときの対応

gulp-concatがうまく動かなかった時のメモ。こんなことでひっかかる人あまりいなそうだけどハマったのでメモしておく。ファイルの更新では上手くいくが、新規作成と削除で上手く動かなかった。ディレクトリの階層が深くなるとダメなのかなとか思ったけど全然関係なかった。

うまくいかない

var gulp = require("gulp"),
  concat = require("gulp-concat");

gulp.task("js.concat-controllers", function() {
  return gulp.src("./src/controllers/**/*.js")
    .pipe(concat("controllers.js"))
    .pipe(gulp.dest("build"));
});

gulp.task("watch", function() {
  gulp.watch(["./src/controllers/**/*.js"], ["js.concat-controllers"]);
});

こうしたらうまくいった

var gulp = require("gulp"),
  concat = require("gulp-concat");

gulp.task("js.concat-controllers", function() {
  return gulp.src("src/controllers/**/*.js") // ★先頭の「./」を削除
    .pipe(concat("controllers.js"))
    .pipe(gulp.dest("build"));
});

gulp.task("watch", function() {
  gulp.watch(["src/controllers/**/*.js"], ["js.concat-controllers"]);// ★先頭の「./」を削除
});

以上です

やっぱりphpのスクリプトはcronに直接設定しないほうがいいかもしれない

また初歩的なことでつまづいてしまった。ありがちなミスで開発中にコマンド上で実行してうまくいってたけどcronに登録したらエラーになってたってやつ。スクリプト内で呼び出す外部ファイルとかフルパスで書いておけば問題ないくらいで最近この形にしてたけどうまくいかないことがあって原因わかるのに時間かかった。

こんなかんじのcron設定

5 10 * * * php /path/to/script.php
5 10 * * * PATH="/usr/local/bin:$PATH" php /path/to/script.php

cronに設定されたスクリプトはそのままだとbashrc、bash_profileあたりが読み込まれないので環境変数まわりがシェルでログインしての開発中とだいぶ状況が異なる。

script.sh

#!/bin/bash -l                                                                                                                                                                                                     
php /path/to/script.php

こんなかんじにcron設定

5 10 * * * /path/to/script.sh

まぁ、cron内でPATHとかちゃんと設定してから呼べば問題ないとは思うのだけど。こっちの方が間違いなさそう。以前はこうやってたけどいつのまにか直接phpファイル実行するように書いてた。。。以上です