カテゴリーアーカイブ JavaScript

asaba 著者:asaba

【react】setectタグで生年月日フォームを作る

ハイブリッドアプリ必須の開発においてはhtml5の知識が必須になりますが、中でもinputタグには誰もがお世話になっていると

思います。そのinputタグのtype(属性)の一つであるdateについて語っていきます。

このdate属性なのですが、ブラウザやデバイスによって表示が変わる仕様になっており、デバイスに至ってはtext扱いに

なってしまい使えない場合があったりと中々癖が強いオブジェクトです。

iosでは、通常のdatepickerのように上下スクロールすることで数字を選べるようになっているのですが、android(特にエクスペリア)

ではカレンダーUIとして表示される仕様になっており、年配な方やせっかちな方にとってはなかなかに見にくい構成に

なっています・・・。

 

アプリの仕様上ユーザー登録画面で生年月日を出力したかったので、一番初めに目にするであろうページでいきなり

イライラさせてしまうことは開発者としては避けたいところ。

これではいけないと思い、date以外にも様々な属性を手探りで使ってみました。(ネタばれですが結果全部不採用w)

 

まず、type=”month”ですがこれは西暦と月はピッカーで表示されるのですが日にちは対象ではないので即対象外。

次にdateTime-localですが、こちらは西暦月日にち三点全部ピッカーとして表示されます。やったネ!と思ったのですが

よく見たら時刻も必ず入力しないといけないんじゃないですかー・・・。

hiddenで非表示にできないか頑張ったのですがダメでしたね、やっぱり入力しないといけないみたいです。

先ほども言った通り生年月日なので産まれた時間まではさすがに求めてないですよ・・・。

しかもIEやfirefoxでは対応していないという仕打ち。

そのほかにも試したのですが、全部撃沈しました。

 

結局selectで生年月日をずらーっと出すようなかたちに落ち着きそうです。

こちらをreactで実装するのは比較的簡単で、まずthis.stateにyear,month,dayをコンストラクタに設定して

mapでそれぞれ西暦月日にちの配列を作ってあげて表示をします。

ただ表示するだけならこれだけでできますが、2018/3/1のように生年月日が連結されたような疑似的にdateで出力される

ような見た目にしたかったのでこんな感じにしました。

<pre>    const year = this.state.year;
    const month = this.state.month;
    const day = this.state.day;
    const birthday = ( year + '/' + month + '/' + day );
</pre>

細かいことを気にしないならば連結するだけならこんな簡単にできてしまいます。

値もしっかりとれているのでandroidでカレンダー表示のUIは嫌だよーというかたは使ってみてくださいね。

 

本日はこんな感じで終了です。よいお年を!

  • この記事いいね! (0)
村上 著者:村上

【Cordova】カメラを起動orギャラリーから写真を選択するプラグイン「cordova-plugin-camera」

ちょっと今更な感じはありますが、アプリでカメラを起動する、またはギャラリーから写真を選択できる「cordova-plugin-camera」のご紹介です。

GitHubのページは下記からどうぞ。

GitHub – apache/cordova-plugin-camera: Apache Cordova Plugin camera
https://github.com/apache/cordova-plugin-camera

Qiitaの記事ではこちらがおすすめです。

[*Cordova*] カメラプラグインを使ってみる – Qiita
https://qiita.com/cigalecigales/items/b81e95065982acb8aede

少し古い記事ですが、とても分かりやすいです。

 

さて、使い方です。
まずインストールですが、こちらのコマンドを実行します。

cordova plugin add cordova-plugin-camera

で、カメラを起動する場合は下記のように記述します。

// カメラを起動
navigator.camera.getPicture(
    cameraSuccess, 
    cameraError, 
    {
        quality: 100,  // 写真のクオリティ(0~100)
        destinationType: Camera.DestinationType.DATA_URL,  // 戻り値のフォーマット
        sourceType: Camera.PictureSourceType.CAMERA  // カメラで撮影
    }
);

// 写真撮影 成功
function cameraSuccess(result){
    // 成功時の処理
    var img = document.getElementById("image");
    img.src = "data:image/jpeg;base64," + result;
}
// 写真撮影 失敗
function cameraError(error){
    // エラー時の処理
}

カメラを起動する場合は、navigator.camera.getPicture() を実行します。
そして関数の第一引数では実行成功時に実行する関数を、第二引数では実行失敗時に実行する関数を指定します。
第三関数では関数のオプションを設定します。
今回は、写真のクオリティ・戻り値のフォーマット・ソースタイプを指定しています。
ソースタイプは、今回は Camera.PictureSourceType.CAMERA をしており、こちらは端末のカメラを起動しています。
なお、写真のライブラリを起動する場合は Camera.PictureSourceType.PHOTOLIBRARY で、アルバムを起動する場合は Camera.PictureSourceType.SAVEDPHOTOALBUM を指定します。
…写真ライブラリとアルバムはどう違うのか…今後検証したいと思います。

オプションはほかにもあり、外側 or 内側のカメラのどちらを起動するかや、写真撮影後に端末に画像を保存するかどうかも指定できます。
このあたりは、上で挙げた GitHub のページか Qiita の記事をご確認ください。

 

カメラプラグインの基本的な使い方は以上です。
が、個人的にはカメラ起動かギャラリー起動かを選べるとなおいいのですが…そういうプラグインは見つけられず…。
何かいい方法はないものか、現在模索中です。

  • この記事いいね! (0)
asaba 著者:asaba

【cordova-react】初期値がundefinedで警告受けた話

componentDidMount()内で値を受け取る処理の途中でWarning: `value` prop on `input` should not be null.という警告を

もらいました。これは、value内の値はnullで受け取ってはいけません、必ず空の状態で設定してください。

という意味になります。

componentDidmount()は、マウントされる際に一回だけ実行されます。筆者は前ページに戻った時に値を受け取る処理を作ったのですが

本来ならば空の状態でrenderされるにも関わらずその時に前ページから判別不能な値nullを既に受け取った状態で

コンポーネントを生成したので警告を受けたのだと思われます。

  componentDidMount() {
    // 前ページから受け取った値をsetStateしている
    const getName = window.localStorage.getItem('nameKey');
    
    this.setState({name: getName});

}

下のコンストラクタでnameを初期化していましたが、さきほどの関数内で先行してnullの値をsetStateしてしまっているので

これでは怒られる訳ですね・・・

 


constructor(props) {
    super(props);
    // 画面初期表示時の状態(state)を読み込む為のキャンセル可能なプロミス(Promise)を初期化する
this.state = {
      name: '',
    }
}

どうしてもコードを変えずに回避したい場合はinputタグ内でvalue = {this.state.name || ”}と書けば解決できます。

 

 名前<input type = "text" value = {this.state.name || ''} onChange = {this.handleNameCodeChange}></input>

参考にさせていただいたサイト→https://github.com/mozilla-services/react-jsonschema-form/issues/336

  • この記事いいね! (0)
村上 著者:村上

【React】onClickが呼び出されたときに任意の値の引数を渡す

React の書き方に未だに慣れていないところがあるので、まとめ。
今回は、onClick で呼び出した関数に、任意の引数を渡す方法です。

参考にさせていただいた記事はこちらから。

【React】イベントハンドラで引数を使いたい【備忘録】 – Qiita
https://qiita.com/tsuuuuu_san/items/73747c8b6e6e28f6bd23

 

上記の記事内でも書かれていますが、Reactの場合、下記のように書いても動きません。

sample(num) {
    // 行いたい処理
}

render() {
    return (
        <div>
            <button onClick={this.sample(100)}>ボタン</button>
        </div>
    );
}

記事によると、引数は渡せたものの、画面描画のたびに押していないはずのボタンの関数が実行されたとのことです。

で、解決策としては、下記のような書き方があるとのこと。
一つ目がこちら。

<button onClick={ () => this.sample(100) }>ボタン</button>

しかし、上記の方法だと、描画のたびに関数を作成することになるため、あまり良くない書き方だそうです。

二つ目がこちら。

<button onClick={ this.sample.bind(this, 100) }>ボタン</button>

何故動くのかは分かりませんが、とにかく動きました、とのこと。
引数が一つであればすっきりとしているので、個人的には好きな書き方ですね。
ですが、やはり何故動くかわからないものを使うのは少々怖いので、使用は見合わせかな。

三つ目がこちら。

sample(e) {
    console.log(e.currentTarget.getAttribute('data-num'));  // 100
}

render() {
    return (
        <div>
            <button onClick={this.sample} data-num="100">ボタン</button>
        </div>
    );
}

こちらでは、HTML5 から導入された、カスタムデータ属性を使用しています。
これは無理矢理感がなくて一番きれいかな、と思いますね。
ということで、今後は3番目のカスタムデータ属性を利用しようと思います。

 

以上、Reactで関数に引数を渡す方法でした。
と言うか、いい加減にReactの書き方に慣れたい…。頑張ります。

  • この記事いいね! (0)
asaba 著者:asaba

【cordova-react】値を動的に次ページに渡す方法

axiosなどの非同期通信を絡めた開発をしているとどうしても単純な画面遷移のことを忘れそうになってしまいます。

ただ単純に遷移だけするならば this.props.history.push({pathname: ‘/next’)}でいけますが、値をもって遷移だと始めたばかりの方は

?となってしまいがちですよね。基礎中の基礎なのでネットにもたくさん情報がありますが、コードには個人差があるのでどうしても

どれを参考にしたらいいか分からない、長くて知らない文法も書かれているから今の自分には理解し難いなど頭を抱えてしまうことも

多いと思います。自分も辛酸を嘗めてきた身ですので、ここでは可能な限り簡潔に書きまとめて同じ悩みを抱えてる方の助けに

なればいいなと思っています。分かりにくかったらごめんなさい。

 

とりあえず値をもって遷移させるコードがこちらです。↓


main.js

this.props.history.push({pathname: '/next', state: { name: this.state.name }});

 

現在の値であるstateを引数にして飛ばしています。これだけで次のページで値nameを扱うことができます。

 

めっちゃ簡単ですね。明解ですね。じゃあ次のページではどうやって受け取るの?ってなった時はこちら↓


next.js
constructor(props) {
    super(props);
    this.state = {
      name: this.props.location.state.name,
    }
}

this.props.location.state.nameとは、タグに格納されたname(値を)意味しています。つまり、前ページでタグで受け取った

値nameをthis.stateのnameキーに値として登録しています。

コンストラクタ内でconsole.log(prop)すると、locationタグの中にしっかりとnameの値が入っており

これで取ってきているのが確認できます。

これでnext.js内のrender(){}内で

{this.state.name}

と定義すればnameの値を表示させることができます。

ざっくりでしたがどうでしょうか。これがすらすら書けるようになれば初級者も卒業できて次のタスクも見えてくると思います。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】端末内のファイルを開く「cordova-plugin-file-opener2」をiOSでも使う

先日投稿した、「cordova-plugin-file-opener2」を使って端末内のファイルを開く方法の、iOSバージョンです。
思ったよりも簡単に実装できました。

プラグインはこちらからご確認ください。

GitHub – pwlin/cordova-plugin-file-opener2: A File Opener Plugin for Cordova
https://github.com/pwlin/cordova-plugin-file-opener2

ちなみに先日の投稿についてはこちらから。

【Cordova】端末内のファイルを開くプラグイン「cordova-plugin-file-opener2」
https://cpoint-lab.co.jp/article/201812/【cordova】端末内のファイルを開くプラグイン「cordova-plugin-file-op/

 

さて、実装方法ですが、コード自体は下記のとおりです。

let filePath = [開きたいファイルのパス];
if (window.device.platform === 'Android') {
  filePath = filePath.replace(/^file:\/\//, '');
}
window.cordova.plugins.fileOpener2.open(
  filePath,
  'image/png',
  {
    error: function() {
      // エラー時の処理
    },
    success: function() {
      // 成功時の処理
    },
  }
);

異なる点は開きたいファイルを指定しているパス値のみで、それ以外は先日に投稿したコードとほぼ同じです。

Android と iOS では開くファイルのパス指定方法が異なるので、まずは端末が Android なのか iOS なのかを判断します。
上記のコードでは、3行目にあたります。
使用しているプラグインは「cordova-plugin-device」です。

GitHub – apache/cordova-plugin-device: Apache Cordova Plugin device
https://github.com/apache/cordova-plugin-device

device.platform で、Android や iOS などの、プラットフォームを示す文字列が取得できるので、それを使って判断しています。
で、Androdだったら、文頭についている file:// をとり、iOS だったらそのままです。

あとは、取得・整形したファイルパスとファイルのMIMEタイプを fileOpener2 のプラグインで指定して、ファイルを開く処理を実行します。
そうすれば、指定したファイルが展開されるはずです。

 

以上、iOSで端末に保存されたファイルを開く方法でした。
Androidは、サンプルコードから文頭の file:// が不要ということが分かったのですが、iOSの指定方法が見つけられず…。
で、試しに取得したファイルパスを加工せず、そのまま指定したところ、問題なく実行されたという次第です。
行き当たりばったりな気もしますが、動いたので問題なし!ということにします。

ということで、Android・iOSの両端末でのファイル展開機能の実装については、これで対応が完了です。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】端末内のファイルを開くプラグイン「cordova-plugin-file-opener2」

前回、端末に画像や音声ファイルをAndroidなどの端末にダウンロードするプラグインを紹介したので、今回は端末内のファイルを開く方法について。
使用したプラグインは「cordova-plugin-file-opener2」です。

GitHubは下記からご確認ください。

GitHub – pwlin/cordova-plugin-file-opener2: A File Opener Plugin for Cordova
https://github.com/pwlin/cordova-plugin-file-opener2

 

プラグインの導入は、例のごとく下記のコマンドを実行します。

cordova plugin add cordova-plugin-file-opener2

使い方はとても簡単で、下記のように開きたい端末内のファイルのパスと、その MIMEタイプを指定するだけ。

cordova.plugins.fileOpener2.open(
    [開きたいファイルのパス], 
    [ファイルのMIMEタイプ], 
    {
        error : function(){
            // ファイル展開 失敗時に実行する処理
        }, 
        success : function(){
            // ファイル展開 成功時に実行する処理
        } 
    } 
);

ファイルのパスは、/storage/emulated/0/Pictures/[ファイル名].jpg のような感じで指定します。
こちらのパスの値については、私の環境では、ファイルダウンロードに成功した時に取得できる file:///storage/emulated/0/Pictures/[ファイル名].jpg から、file:// を取ったものを使っています。

ご覧の方の環境に合うかは分かりませんが、参考にコードを記載しておきます。

window.document.addEventListener('DOWNLOADER_downloadSuccess', function(event) {
  const data = event.data;
  const filePath = data[0].nativeURL.replace(/^file:\/\//, '');

  if (fileMIMEType !== null) {
    window.cordova.plugins.fileOpener2.open(
      filePath,
      'image/png',
      {
        error: function() {
          // ファイル展開失敗時の処理
        },
        success: function() {
          // ファイル展開成功時の処理
        },
      }
    );
  }
});

こちらはとりあえずAndroidで動作するようにしてあるだけなので、iOS には対応していません。これからやります。
なお、MIMEタイプについても、とりあえず png 形式のみ対応なので、もし扱うファイル種類が定義されていない場合は、拡張子で jpg、gif くらいは判断できるようにしたほうが良さそう。

ちなみに、動作確認中に、うっかり音楽ファイル(mp3)を imgae/png で開いてしまいましたが、エラーにはならず、ファイルが壊れているような表示になりました。
その後、きちんと audio/mp3 にしたら、開くアプリの選択肢が表示され、再生もできるようでしたので、音声ファイルも問題なさそうです。

 

以上、Android端末内のファイルをアプリで開く方法でした。
とりあえず、Androidに問題がなかったので、iOS でも使えるように修正していきたいと思います。

  • この記事いいね! (0)
村上 著者:村上

【Cordova】端末にファイルをダウンロードするプラグイン「cordova-plugin-file-downloader」【解決済】

昨日投稿した、「cordova-plugin-file-downloader」について、問題なく動作させることができたので…というか、ダウンロードできていたことが分かったので、それのご報告です。

昨日の記事はこちらから。

【Cordova】端末にファイルを保存するプラグイン「cordova-plugin-file-downloader」【未動作】
https://cpoint-lab.co.jp/article/201811/【cordova】端末にファイルを保存するプラグイン「cordova-plugi/

 

ダウンロードしたファイルの確認方法ですが、私の端末(Android 7.0)では「ダウンロード」アプリから確認ができました。
まず、アプリ一覧から「ダウンロード」アプリを開き、サイドメニューから、端末のローカルストレージを選択します。
画面イメージは下記のとおりです。

ローカルストレージを選択すると、フォルダ一覧が表示されるので、ここからプラグインの初期設定時に folder で指定したフォルダ名を探します。
無事見つかれば、このフォルダ内にダウンロードしたファイルが保存されているはずです。

ちなみに、そのコードはこちら。

downloader.init({folder: "[端末の保存先ファイル名]"});

ということで、ただ単に私がダウンロードが完了したファイルを探せなかっただけでした!
大変失礼致しました…!

 

さてしょうもない結末だったので、ダウンロード後の処理を記述する方法についてご紹介したいと思います。
オプションに onSuccess とかの指定ができなかったので、てっきり出来ないかとも思いましたが、ちゃんとありました!
コードは下記のとおりです。

document.addEventListener('DOWNLOADER_downloadSuccess', function(event) {
  const data = event.data;
  console.log(data[0].name);
  console.log(data[0].fullPath);
  console.log(data[0].nativeURL);
});

document.addEventListener の第一引数で、DOWNLOADER_downloadSuccess を指定すると、ファイルのダウンロードに成功した時にこの関数が呼び出されます。
で、変数 event に、データが入っているので、上記のように指定すると、ファイル名や保存先のパスなどが取得できます。

第一引数は、他にも DOWNLOADER_downloadErrorDOWNLOADER_downloadProgress なんかもあるので、ご要望に合わせて使い分けてください。

 

以上、cordova-plugin-file-downloader を使ったダウンロード方法とダウンロードしたファイルの確認方法でした。

  • この記事いいね! (0)
asaba 著者:asaba

【cordova-react】エラー備忘録:propTypeの型を間違えた

コンポーネントのpropの値を渡すときはpropTypeパッケージを使いますが、proptypeの方の指定を間違えるとエラー(Warning: Failed

propType: Invalid prop of type `array`)で怒られてしまいます。これはjsonで受け取る時の型が定義した型と違う時に起きるエラーです。

例えばですが[]javascript]

"point": [
{
"math": 1,
"math": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
},

jsonファイルを見ると、上のmathはkeyと値で定義しただけなので下のように定義をします。



itemKeys: PropTypes.string.isRequired

ところが下のmathは、配列で値を囲んでおり、これをproptypes.stringで定義してしまうと型が違うよと怒られてしまう訳ですね~。

配列の時は下記のように定義して上げましょう。


itemKeys: PropTypes.array.isRequired

stringのところがarrayに変わっただけなので 形式はあまり変わらないです。日本語の記事が少なかったのでもし同じエラーで悩んでいる

かたがいたら参考にしてみてください。

参考URL->https://stackoverflow.com/questions/37063418/warning-failed-proptype-invalid-prop-of-type-array-expected-object-with-re

  • この記事いいね! (0)
村上 著者:村上

【Cordova】端末にファイルを保存するプラグイン「cordova-plugin-file-downloader」【未動作】

Cordovaアプリにて画面にダウンロードボタンを配置し、それをタップしたら、あらかじめ指定しておいた画像ファイルをダウンロードする、という処理を行いたいのですが…現在、絶賛苦戦中です。
今回使用しているプラグインは「cordova-plugin-file-downloader」です。
コードがとてもシンプルで簡単だったので、指定ミスはないはずなのですが…。
エラーが発生しない、私の苦手なパターンにハマっています。

公式ページはこちらから。

GitHub – mramonlopez/cordova-plugin-file-downloader: Phonegap plugin to download a list of files or a single file to the phone, check consistency and unzip if necessary (Android and ios)
https://github.com/mramonlopez/cordova-plugin-file-downloader

cordova-plugin-file-downloader – npm
https://www.npmjs.com/package/cordova-plugin-file-downloader

 

プラグインの導入時は、下記のコマンドを実行します。

cordova plugin add cordova-plugin-file-downloader

もっともシンプルな実装方法は下記のとおりです。

downloader.init({folder: "[端末の保存先ファイル名]"});
downloader.get("[保存したいファイルのパス]");

1行目の初期化については、オプションがいくつかありますが、folder については必須事項なので、必ず指定してください。
例えばアプリ名などの文字列を指定すればよいかと。
他にも、zipファイルをダウンロードした際に、ダウンロード完了後に解凍する unzip や、展開後の zip ファイルを削除する delete オプションもあります。
また、wifiOnly という、Wi-Fiに接続されているときのみダウンロードを行うというオプションもあります。
なお、これはデフォルト値が true なので、あえて指定する必要はなさそうです。

 

プログラムとしては以上なので、こちらを実行すれば動作するはずが…何故かダウンロードできず。
ログには、download [ダウンロードしたファイルのパス] to [端末に保存したファイルのパス] とか、Saved file: [端末に保存したファイルのパス] というメッセージがあったので、ダウンロードできているようにも見えたのですが、いくら探してもダウンロードした画像が見つかりませんでした。
なおインストール時に、下記を config.xml の タグ内に追加しろとあったので、それについては対応しました。

<preference name="AndroidPersistentFileLocation" value="Compatibility" />

こちらのコードの意味は、以前の設定(Compatibility)をそのまま使用してファイルの保存するという意味になるとのこと。
value は Internal という値を指定することも可能で、こちらでは内部の保存場所を使用します。

 

幸い、若干の時間的猶予はあるので、引き続き調査したいと思います。
もしくは、違うプラグインを使うことを検討してもいいかもしれませんね。

  • この記事いいね! (0)