2018年9月26日水曜日

Moment.jsでDeprecation warning(value provided is not in a recognized RFC2822 or ISO format)が発生した場合の対応方法(Angular,Pipe)


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

前回、AngularのPipeを使ってhtml(View)の表示を共通化する。と言う記事を書きましたが、実は実装をしている時に一つハマったことがあります。

最終的な実装の前に記載していたプログラムは以下の通りです。
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    const postDate = moment(value).format('YYYYMMDD');
    const today = moment().format('YYYYMMDD');
    const yesterday = moment().subtract(1, 'days').format('YYYYMMDD');

    let displayDate: string = value;

    if (postDate === today) {
      displayDate = '今日';
    } else if (postDate === yesterday) {
      displayDate = '昨日';
    }

    return displayDate;
  }

}

上記で実行すると・・・・
Deprecation warning: value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are discouraged and will be removed in an upcoming major release. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.
Arguments: 
[0] _isAMomentObject: true, _isUTC: false, _useUTC: false, _l: undefined, _i: 2018/09/01, _f: undefined, _strict: undefined, _locale: [object Object]
Error

とエラーになってしまいます。
momentに引き渡す日付は、ISO形式ではなくていけないようです。 ただ、そもそもの値が文字列なので、文字列操作でISO形式にフォーマットするのが面倒・・・ と言う事で、前回の実装では、
    const postDate = new Date(value);
    const postDateISO = moment(postDate.toISOString()).format('YYYYMMDD');
上記のように一度日付に戻してから、「toISOString()」を使うようにしました。
元々、トラブルの多い「new Date()」を使いたく無いので、momentにしたのですが・・・

と言う訳で、最終的な実装は、前回も記載した通り、
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    const postDate = new Date(value);
    const postDateISO = moment(postDate.toISOString()).format('YYYYMMDD');
    const today = moment().format('YYYYMMDD');
    const yesterday = moment().subtract(1, 'days').format('YYYYMMDD');

    let displayDate: string = value;

    if (postDateISO === today) {
      displayDate = '今日';
    } else if (postDateISO === yesterday) {
      displayDate = '昨日';
    }

    return displayDate;
  }

}

となります。
上記実装を参考にされる方は、タイムゾーンに注意して下さいね。


,

2018年9月25日火曜日

AngularのPipeを使ってhtml(View)の表示を共通化する。


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。

Angularのhtml(View)で変数を展開する場合、中括弧を二つ(double curly braces)で変数を囲みます。
<div>{{ targetDate }}</div>

さて、例えば、この「targetDate」変数に「2018/09/01」のような日付が設定されていて、
その日付が本日であれば『今日』、昨日だったら『昨日』と表示し、それ以外の時だけ、日付をそのまま表示するとします。
そんな時、どんな実現方法があるでしょうか?

「*ngIf」を使う?そもそもTypeScript側で判定しておく?色々とありますが、「*ngIf」を使うと煩雑になって、他に同じような表示箇所があったら、その度に記載する必要がありますし、APIから取得した値などは、html(View)側でリストのまま繰り返し処理を行う、
<ng-container *ngFor="let item of list">
  <div class="hoge">{{item.targetDate}}</div>
</ng-container>
という方法を使う事が多いので、TypeScript側で編集はしないんですよね。

まあ、『そんなのAPI側の責務でしょ』と言われたらそれまでですが、
表示内容に特化しているなら、フロントエンドでやるのも悪手では無いと思います。

さて、話が逸れてしまいましたが、こんな時に役に立つのが、AngularのPipe機能です。

簡単に言うと、htmlに表示する時に同時に変換処理も行い、表示内容を変えてしまう、と言う機能です。

早速使ってみましょう。
angular-cliを利用しているならば、
ng g pipe [path/name]
と言うコマンドでテンプレートを作成出来ます。

今回は、[path/name]の部分を pipe/change-date-format に変えます。
すると、以下のようなファイルが生成されます。
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    return null;
  }

}

この状態で、実装を行なっていきます。
今回、日付の編集・判定には、「moment」を使用します。
momentのインストールと使用方法は省きますが、実装結果は以下のようになります。
import { Pipe, PipeTransform } from '@angular/core';
import * as moment from 'moment';

@Pipe({
  name: 'changeDateFormat'
})
export class ChangeDateFormatPipe implements PipeTransform {

  transform(value: string, args?: any): any {
    const postDate = new Date(value);
    const postDateISO = moment(postDate.toISOString()).format('YYYYMMDD');
    const today = moment().format('YYYYMMDD');
    const yesterday = moment().subtract(1, 'days').format('YYYYMMDD');

    let displayDate: string = value;

    if (postDateISO === today) {
      displayDate = '今日';
    } else if (postDateISO === yesterday) {
      displayDate = '昨日';
    }

    return displayDate;
  }

}

処理は単純で、引数に送られてきた値を日付に変換、形式の統一、そして判定を行い、その日付が本日であれば『今日』、昨日だったら『昨日』、それ以外は日付をそのまま return しています。

Pipeの使い方は、
<div>{{ targetDate | changeDateFormat }}</div>
となります。@Pipe の name をvertical lineで変数に繋げて(Pipe)記載するだけです。簡単ですね。

大規模なプロジェクトになればなるほどPipeを上手く使うと、開発効率が上がります。
それでは、より良いAngularライフを!


2018年9月21日金曜日

Amazon Linux 2 にnginxをインストールする。(Amazon Linux Extrasを使う)


オフィス狛 技術部のKoma(Twitterアカウントの中の人&CEO)です。
今回は完全に自分用の備忘録です。
(毎回同じ問題にぶちあたり、同じ情報を調べるので・・・・)

さて、早速ですが、AWS EC2 のAmazon Linux 2 に、nginxをyumでインストールしようとすると・・・
$ sudo yum install -y nginx
読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd
パッケージ nginx は利用できません。
エラー: 何もしません

nginx is available in Amazon Linux Extra topic "nginx1.12"

To use, run
# sudo amazon-linux-extras install nginx1.12


と、エラーになってしまいます。
・・・まあ、メッセージに解決策があるのですが、
念の為、説明しておくと、Amazon Linux 2には、
Amazon Linux Extras という仕組みがあって、良く使われるソフトウェアの最新バージョンについて、関連パッケージを含めて簡単にインストールすることが出来ます。
AWS自体が提供している仕組みだけあって、OSの安定性を保ったインストール・利用が可能になります。

実際にどんなものを提供しているのか見てみましょう。「amazon-linux-extras」というコマンドを実行してみます。
$ amazon-linux-extras
  0  ansible2                 available  [ =2.4.2 ]
  1  emacs                    available  [ =25.3 ]
  2  memcached1.5             available  [ =1.5.1 ]
  3  nginx1.12                available  [ =1.12.2 ]
  4  postgresql9.6            available  [ =9.6.6  =9.6.8 ]
  5  postgresql10             available  [ =10 ]
  6  python3                  available  [ =3.6.2 ]
  7  redis4.0                 available  [ =4.0.5  =4.0.10 ]
  8  R3.4                     available  [ =3.4.3 ]
  9  rust1                    available  \
        [ =1.22.1  =1.26.0  =1.26.1  =1.27.2 ]
 10  vim                      available  [ =8.0 ]
 11  golang1.9                available  [ =1.9.2 ]
 12  ruby2.4                  available  [ =2.4.2  =2.4.4 ]
 13  nano                     available  [ =2.9.1 ]
 14  php7.2                   available  [ =7.2.0  =7.2.4  =7.2.5 ]
 15  lamp-mariadb10.2-php7.2  available  \
        [ =10.2.10_7.2.0  =10.2.10_7.2.4  =10.2.10_7.2.5 ]
 16  libreoffice              available  [ =5.0.6.2_15 ]
 17  gimp                     available  [ =2.8.22 ]
 18  docker=latest            enabled    [ =17.12.1  =18.03.1 ]
 19  mate-desktop1.x          available  [ =1.19.0  =1.20.0 ]
 20  GraphicsMagick1.3        available  [ =1.3.29 ]
 21  tomcat8.5                available  [ =8.5.31 ]
DBやWebコンテナ、言語、フレームワークなど、色々ありますね。

さて、nginx1.12 が利用可能(available)になっているので、インストールしてみます。
sudo amazon-linux-extras install nginx1.12

これでインストール完了です。もう一度「amazon-linux-extras」というコマンドを実行してみます。
 $ amazon-linux-extras
  0  ansible2                 available  [ =2.4.2 ]
  1  emacs                    available  [ =25.3 ]
  2  memcached1.5             available  [ =1.5.1 ]
  3  nginx1.12=latest         enabled    [ =1.12.2 ]
  4  postgresql9.6            available  [ =9.6.6  =9.6.8 ]
  5  postgresql10             available  [ =10 ]
  6  python3                  available  [ =3.6.2 ]
  7  redis4.0                 available  [ =4.0.5  =4.0.10 ]
  8  R3.4                     available  [ =3.4.3 ]
  9  rust1                    available  \
        [ =1.22.1  =1.26.0  =1.26.1  =1.27.2 ]
 10  vim                      available  [ =8.0 ]
 11  golang1.9                available  [ =1.9.2 ]
 12  ruby2.4                  available  [ =2.4.2  =2.4.4 ]
 13  nano                     available  [ =2.9.1 ]
 14  php7.2                   available  [ =7.2.0  =7.2.4  =7.2.5 ]
 15  lamp-mariadb10.2-php7.2  available  \
        [ =10.2.10_7.2.0  =10.2.10_7.2.4  =10.2.10_7.2.5 ]
 16  libreoffice              available  [ =5.0.6.2_15 ]
 17  gimp                     available  [ =2.8.22 ]
 18  docker=latest            enabled    [ =17.12.1  =18.03.1 ]
 19  mate-desktop1.x          available  [ =1.19.0  =1.20.0 ]
 20  GraphicsMagick1.3        available  [ =1.3.29 ]
 21  tomcat8.5                available  [ =8.5.31 ]

nginx1.12 が使用出来る状態(enabled)になっています。

念の為、コマンドを実行してみます。
 $ nginx -v
nginx version: nginx/1.12.2

無事にインストール出来ているようです。

以上、本当に備忘録でした。


, , ,

2018年9月19日水曜日

knex.js の transaction でなぜか delete されないときに注目すること。


オフィス狛 技術部 CTOの Taka-yamです。

knex.jsは、Node.jsでActiveRecordを用いてSQLを発行するライブラリです。
fluentにSQLを構築でき、大変便利だなと感じる一方で、
トランザクション中にSELECT分を使用する際にちょっとした落とし穴があり注意が必要です。

例えば、booksというidとnameを保存するシンプルなテーブルがあるとして考えます。
id |  name  |
---+-------------+
 1 |  我輩は猫である|
 2 | こころ       |
 3 | 三四郎       | 

例えば、このテーブルのid1のデータを 削除->存在チェック->登録と実行します。
// knexの定義
const knex = require('../db/knex');

knex.transaction(trx => {
    
    // 全て削除
    knex.from('books').del();

     // 消えているか確認(存在チェック)
    const user = knex.from('books') . where('id', 1).first();

    if (typeof user !== 'undefined') {
        throw new Error(' データがあるよ')
    }

    // 登録
    const books = {id: 1, name: '銀河鉄道の夜'}
    knex.insert(books).into('books');
}

上記の メソッドは存在チェック後のifでエラーを投げます。

なぜか?

これは selectがクロージャ内に渡されているKnex.Transactionインスタンスを使用していない ため、
トランザクションとは別に処理を走らせてしまっているためです。

クロージャ内にいるので一見すると同じトランザクション として扱われるのかなと思ってしまいますが、実際には下記のようにしないといけません。
knex.transaction(trx => {
    
    // 全て削除
    trx.from('books').del();

     // 消えているか確認(存在チェック)
    const user = trx.from('books').where('id', 1).first();

    if (typeof user !== 'undefined') {
        throw new Error(' データがあるよ')
    }

    // 登録
    const books = {id: 1, name: '銀河鉄道の夜'}
    trx.insert(books).into('books');
}

selectに関しては下記のようにも 書けます。
const user = knex.transactioning(trx).from('books') . where('id', 1).first();

例えば処理を共通化して別メソッドとして切り出したりしていると、
思わぬところでトランザクションが途切れてしまっていることがあり、
「???」になることがあります。

また、個人的にですが、Realmなどのライブラリですと、
クロージャ内がトランザクション領域として扱われるので
勘違い して同じように使用してはまってしまったという経緯もありました。

もし同じような現象で困っている方がいらっしゃいましたら、
上記のような可能性も考えてみてください。

,

2018年9月3日月曜日

Illustratorでカラーバリエーションのあるようなアイコンやイラストをできるだけ楽に作る。


こんにちは、オフィス狛デザイン部のSatoです。

今回はカラーバリエーションのあるようなアイコンをできるだけ楽に作る方法をご紹介したいと思います。
アプリ内の画像などを作っている時に背景色によってアイコンの色が変わったり、状態によってアイコンカラーが変わったりするときの画像がすこーし簡単に作れるようになります。


Illustratorで描いたイラストです。
パーツが少し多いのでもうちょっと一部の色を明るくしたいなと思ったり、カラーバリエーションのある画像が欲しいと思うとちょっと大変ですよね。
こういう時に使える機能が「オブジェクトを再配色」機能です。


まず色を変えたいオブジェクト全体を選択し、Illustratorメニューバーの「編集」の「カラーの編集」から「オブジェクトを再配色」を選ぶかツールバーのオブジェクトを再配色アイコン」クリックします。

下のようなオブジェクトを再配色パレットが出てきます。

編集ボタンを押すと色相環のような画面になるので右下の「ハーモニーカラーをリンク」ボタンをクリックしておきます。(これをクリックするとまとめて色相や彩度が変わります)
色相環のような図の中の丸い色つきの丸を移動させると色相が変わるのでこれで一気に全体的な色が変えられます!

色を変えてみました。


一部だけ色が変えたい場合は「ハーモニーカラーをリンク」ボタンを押さずに変えたい部分の色のみの位置を動かしたり、指定画面(編集ボタンの横にある「指定」ボタンで画面が戻ります)から色を変えたりできます。

一部色を変えてみました。

簡単に絵のカラーパターンができました!

グラデーションで使われている色などもこの機能で変えられるので、カラーバリエーションのある画像がササッと数枚作れます。
使う機会が多そう&時短になる機能なので、ぜひ使ってみてください。