はじめに
kintone UI Componentがベータ版から正式版(v1)になって、とてもシンプルにいい感じになりました。
便利に使わせてもらっております!
import { Text } from 'kintone-ui-component'
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text)
})
ただ、やっぱり使っていると「ここは<input type="date">
にしたいなぁ」とか、UI Componentで対応してない属性を使いたい場合とかあるんですよ。
そのやり方がちょっぴり複雑だったのでメモしておきます。
TL;DR
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text) // appendしないと配下はnull
setTimeout(() => {
// レンダリング終わるまで待ってからsetAttribute
text.querySelector('input').setAttribute('type', 'date')
}, 1000)
})
JSで普通にHTML要素を作成する場合
setAttributeを使って色々と属性を設定できます。
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = document.createElement('input')
text.value = '2021-04-20'
text.setAttribute('type', 'date')
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text)
})
kintone UI Componentの場合
失敗例1
こうすれば行けそうな気がしますが、まったくダメです。
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
text.setAttribute('type', 'date')
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text)
})
UI Componentで作ったtext要素は、実はけっこう複雑なHTML構造をしてて、
こんな感じで<div>
<span>
がたくさんネストされてます。
一番外側のタグは<kuc-text>
みたいなWeb Componentsのカスタムタグでした!
<kuc-text>
<style>
(略)
</style>
<div class="kuc-text__text" style="width: 192.5px;">
<label class="kuc-text__text__label" for="xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx-label" hidden="">
<span class="kuc-text__text__label__text"></span
><span class="kuc-text__text__label__required-icon" hidden="">*</span>
</label>
<div class="kuc-text__text__input-form">
<div class="kuc-text__text__input-form__prefix-outer">
<span class="kuc-text__text__input-form__prefix-outer__prefix" hidden=""></span>
</div>
<div class="kuc-text__text__input-form__input-outer" style="width: 100%;">
<input
class="kuc-text__text__input-form__input-outer__input"
type="text"
id="xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx-label"
placeholder=""
textalign="left"
aria-required="false"
aria-invalid="false"
aria-describedby="xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx-error"
/>
</div>
<div class="kuc-text__text__input-form__suffix-outer">
<span class="kuc-text__text__input-form__suffix-outer__suffix" hidden=""></span>
</div>
</div>
<div class="kuc-text__text__error" role="alert" id="xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx-error" hidden=""></div>
</div>
</kuc-text>
developer Networkの記事kintoneライクなスタイルシートの利用にある構造と似てます。これを意識せずにパッと使えるようにしてくれているライブラリということですね。
上に書いたJSだと、<kuc-text type="date">
になるだけで、何の意味もないわけですね。
子要素の中心部<input>
を狙ってsetAttribute
してやらないといけません。
失敗例2
<input>
要素はコンポーネント配下に1つしかないので、これで行けそうな気がしますが、やっぱダメです。
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
text.querySelector('input').setAttribute('type', 'date')
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text)
})
この場合、text.querySelector('input')
の結果がnull
になっちゃうんですね。
一方、ブラウザのコンソールでtext.querySelector('input')
を直接走らせると、ちゃんと動く。
レンダリングの時間が少しかかるので、それを待たねばならぬのです。
失敗例3
1秒ほど待機してみることにしましょう。
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
setTimeout(() => {
text.querySelector('input').setAttribute('type', 'date')
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text)
}, 1000)
})
これも、結果はダメ。
実はnew Text()
しただけでは、いくら待っても配下の要素はnull
のままで、appendChild()
で表示中のページに追加して初めて、配下のレンダリングが始まるようです。このあたりの背景は詳しくないんですが、パフォーマンス上の理由かと思われます。
成功例
appendChild()
してから待機することで、うまく動きました!
kintone.events.on(['app.record.edit.show', 'app.record.create.show'], (event) => {
const text = new Text({ value: '2021-04-20' })
kintone.app.record.getHeaderMenuSpaceElement().appendChild(text) // appendしないと配下はnull
setTimeout(() => {
// レンダリング終わるまで待ってからsetAttribute
text.querySelector('input').setAttribute('type', 'date')
}, 1000)
})
この「1秒待ち」というのはあてずっぽうなので、PCのスペックなどによってはもっと待たなければいけなかったり、もっと短くて十分な場合もあります。
本当にちゃんとやるなら、MutationObserver使ってしっかりと監視することになるのでしょうが、そこまではオーバーキルだと思うので、まぁ「ちょっと待機」で十分かなーと個人的には思います。
サイボウズさんへ
こんな風に、カスタムアトリビュートを自由に設定できるようになると嬉しいっす!
循環参照ですが、Issue送ってみました。
new Text({ value: '2021-04-20', attribute: { type: 'date' } })
でも「ラベルのattribute」とか「途中のdivのattribute」とか
言い出すと切りがないから難しいかなぁ。。。
追記)
やはりカスタムAttributeは無理ってことでした。
Date系のコンポーネントはそのうち出るらしいので、
そのあたりが充実したら、setAttributeする機会も減るでしょうね。
では今日はこの辺で~。またお会いしましょう