2022年4月27日水曜日

AlertDialog上のradioボタンの選択状態が更新されない

 最近、Flutterを使った開発にも慣れてきて、なんとなくFlutterがわかった気になっていたところにタイトルの状況にぶち当たって、目の前が真っ暗になりました。

AlertDialog上でRadioボタンの選択状態を変更しても画面上では選択状態が更新されませんが、AlertDialogを閉じて再度開くと選択状態は更新されているので、表示更新の問題であることがわかります。

馬鹿の一つ覚えでsetState()で表示更新させればいいんでしょと思っていたので、setState()を使っているのに表示が更新されないとわかって、まさに絶望の淵に立たされたのでした。

しかし、Flutterユーザーも増えてきた昨今では、先人がネットに情報をあげてくれています。本当にありがたいことです。

それによると、StatefulBuilderを使う必要があるとのこと。

StatefulBuilderの説明にある、プラトニックウィジェット(platonic widget)ってなんだ?、と思いましたが、まあ、今回の場合で考えれば、AlertDialog内のRadioで呼ばれたsetState()を、AlertDialogの外に伝えてくれるだけの役割を果たす観念的なウィジェットという感じでしょうか?

2022年1月31日月曜日

Avoid using web-only libraries outside Flutter web plugin packages.と怒られる

 Flutter web でブラウザをリロードされた際に、その時表示されていたページによって処理を分岐したくて、dart:htmlをimportしてwindow.location.hrefでURLを取得していたら、Avoid using web-only libraries outside Flutter web plugin packages.と怒られるのだが、じゃあ、どうすればいいんだよ!としばらく放置していた。

Uri.base を使えばいいそうだ。

The natural base URI for the current platform.

When running in a browser this is the current URL of the current page (from window.location.href).

When not running in a browser this is the file URI referencing the current working directory.

 

2022年1月17日月曜日

Flutter 開発メモ

 開発中に使用したが、結局使わなくなったのでソースから削除するけど、後で使うかもしれない機能メモ

指定した型の一番近い祖先Widgetを返す

MyApp? myApp = context.findAncestorWidgetOfExactType<MyApp>();

2022年1月13日木曜日

Flutter web でmanifest.jsonが401エラーになる

開発中のFlutter webアプリをサーバにデプロイしてChromeでアクセスしたら、DevToolsのコンソールで、manifest.jsonが 401エラーになっているのがわかった。

なんだよ気持ち悪いなぁと調べていたら、まだ開発中ということでデプロイ先のフォルダにBasic認証をかけているのが原因らしい。

index.html内の

<link rel="manifest" href="manifest.json">

を、以下のように変更したら解消した。

<link rel="manifest" href="manifest.json" crossorigin="use-credentials">

参考 MDN



Flutter web をドキュメントルート以外に設置する

 Flutter web をドキュメントルート以外に設置する方法は、Flutterのドキュメント(Configuring the URL strategy on the web)のHosting a Flutter app at a non-root locationに以下のように書かれている。

Update the <base href="/"> tag in web/index.html to the path where your app is hosted. For example, to host your Flutter app at myapp.dev/flutter_app, change this tag to <base href="/flutter_app/">.

これを受けて、私もbuild/web/index.htmlを直接書き換えていたが、忘れてそのまま設置してしまう可能性もあり、何とかならないのかと思って、build下ではなくプロジェクト直下のweb/index.htmlをみると、以下のように変数指定されている。

<base href="$FLUTTER_BASE_HREF">

これは、どこかで設定しておけるはずだと思い、いろいろ探してみたがそれらしい場所がない。

ターミナルでhelpすると、

> flutter help build web

Usage: flutter build web [arguments]

--base-href                        Overrides the href attribute of the <base> tag in web/index.html. No change is done to web/index.html file

なるほど、上記のドキュメント例なら、以下のようにbuildすればいいということか。

> flutter build web --base-href "/flutter_app/"

ドキュメントに一言、書いておいてください。

2021年7月1日木曜日

Element PlusのDatePickerで週の開始日を指定する

 ElementのDatePickerではfirstDayOfWeekを指定することによって、週の開始日(曜日)を指定することができた。

ところが、Element PlusのDatePickerでは、そのようなオプションが見当たらない。

https://github.com/element-plus/element-plus/issues/1055によると、代わりにDay.jsのロケールを使ってねということらしい。

例えば、Day.jsのアフリカのロケール(af.js)には、以下のような記述が含まれている。

weekStart: 1

これを使うらしい。

日本のロケール(ja.js)には、そのような記述が含まれていないが、追記したものを別ロケール(ja-my.js)として保存した。

通常は、

import ElementPlus from 'element-plus'
import locale from 'element-plus/lib/locale/lang/ja'

createApp(App).use(ElementPlus, { locale })

とすることで、Day.jsのロケールも自動的にセットされるのだが、

import 'dayjs/locale/ja-my'
dayjs.locale('ja-my')

を追加することで、今回作成した週の開始日が指定されたロケールを指定できるようだ。

以下は、土曜日を週の開始日に設定した例


ちょっと、これはドキュメントを読んでもわからないよなぁ。
もっとも、こんな変則的な曜日並びのカレンダー表示させるほうがおかしいと言われれば、その通りなんだけど。


2021年6月4日金曜日

VueアプリケーションのVersion管理(キャッシュ対策)

 VueでSPAアプリケーションをつくってWebに公開すると、はじめから予想されたことだが、ブラウザにキャッシュされるので、サーバにおくアプリケーションのバージョンをあげても、ローカルの古いバージョンのまま使用するユーザーが発生する。

やはり、最初にサーバから現在のバージョン番号を取得して、自分自身(ローカル)のバージョンと異なったらリロードしてもらうのがいいだろう。

自分自身のバージョンは、package.jsonのversionを利用することにしよう。

import { version } from '../../package.json'

なお、上記で以下のエラーが出る場合は、

Cannot find module '../../package.json'. Consider using '--resolveJsonModule' to import module with '.json' extension.Vetur(2732)

tsconfig.jsonに、以下を追加する。

"compilerOptions": {
↓↓
  "resolveJsonModule"true,
↑↑

アプリケーションが表示されたら、最初にサーバにアクセスしてバージョン番号を取得し、自分自身のバージョンと比較して異なる場合は、以下のようにリロードする。

location.reload()

リロードした結果、サーバとローカルのバージョンが一致すれば「更新しました」、一致しなければ「更新できませんでした」のようなメッセージをそれぞれ表示させる。

くれぐれも、一致するまでリロードが無限ループしないように注意。

当該処理が、リロード後であることを判断する方法は、いろいろあるようだが、検証が面倒なので、今回はsessionStorageを使った。

location.reload(true)がdeplicatedになって、location.reload()だとキャッシュ読んじゃうんじゃないかと心配したが、ちゃんと更新してくれたのでとりあえず、深入りしないことにしよう。