【kintone UI Component】Textコンポーネントのスタイル変更について

【実現したいこと】

kintone UI Component で作成したTextコンポーネントに対し、

focus イベント時に背景色を変更したい。

(また、cssファイル作成は極力避け、jsファイル上でcssを変更したい)

 

以下のように書いても色は変わらなかったため、悩んでおります…。

let kui_text = new Kuc.Text({});
kui_text.addEventListener('focus', (event) => {
event.target.style.backgroundColor = '#e2f2fe';
});

※kintone UI Component は ver.1.5.0 を使用しております

3332 さん

Text コンポーネントの背景色は親要素ではなく梱包される input 要素に設定されているため、それを変更すれば問題ありませんでした。

また、フォーカスが外れたとき(blur イベント)に背景色を元に戻したい場合は、Textコンポーネントに対して useCapture = true で addEventListener するか、input 要素に対して addEventListener すれば実現できると思います。

以上になります。不明な点がありましたら、気兼ねなくご質問ください。

川村 さん

ご返信くださりありがとうございます!

 

input 要素のスタイルを変更すればよいとのことでしたので、kintone UI component 上で定義されている

「kuc-text-1-5-0__group__input-form__input-outer__input」classに対し

focus イベントを付与しようとしたのですが、

下記のように書いてみたところまだ上手く動きませんでした。

(() => {
  'use strict';

  kintone.events.on('app.record.index.show', (event) => {

    let header = kintone.app.getHeaderMenuSpaceElement();

    //重複を避けるため要素をあらかじめクリア
    for (let i = header.childNodes.length - 1; i >= 0; i--) {
      header.removeChild(node_space.childNodes[i]);
    }

    //text配置
    let kui_text1 = new Kuc.Text({});
    let kui_text2 = new Kuc.Text({});
    let kui_text3 = new Kuc.Text({});
    header.append(kui_text1);
    header.append(kui_text2);
    header.append(kui_text3);

    //text component内のinput要素に対して一括でイベント処理を付与
    let input_class = document.querySelectorAll('.kuc-text-1-5-0 __group__ input-form __input-outer__ input');
    input_class.forEach( (target) => {
      target.addEventListener('focus', () => {
        target.style.backgroundColor = '#e2f2fe';
      });
    });

    return event;
  });
})();

動作を確認してみると document.querySelectorAll の結果が NodeList (0) になっており、

どうやらDOM構築前に処理を行っているため input 要素を取得できていないようでした。

どのように修正するのが良いでしょうか…?

3332 さん

下記私の試したサンプルコードになります。イベント発生時には要素が確実にDOMツリーに追加されているため取得できました。背景色を解除する処理も入っています。

let kui_text = new Kuc.Text({});
kui_text.addEventListener('focus', (e) => {
  const input = e.currentTarget.querySelector('input');
  input.style.backgroundColor = '#e2f2fe';
  input.addEventListener(
    'blur',
    () => {
      input.style.backgroundColor = null;
    },
    { once: true }
  );
});
document.body.appendChild(kui_text);

また、要素の重複を避けるコードですが、getHeaderMenuSpaceElement で取得する要素内に他の要素が入りこむことになった場合(プラグインの追加等)影響を受けてしまうため、要素を消さずに存在を確認する方法をお勧めします。

let container;

kintone.events.on('app.record.index.show', (event) => {
  if (!container) {
  container = document.createElement('div');

    // 必要な要素を含める

  const header = kintone.app.getHeaderMenuSpaceElement();
   header.appendChild(container);
  }

  return event;
});

以上になります。不明な点がありましたら、気兼ねなくご質問ください。

川村さん

blurイベントの書き方までご提示くださりありがとうございます!

おかげさまでやりたいことを実現できました!

 

重ねて初歩的なことで恐縮なのですが、

要素の重複を避けるコードにつきまして確認させていただきたいことがございます。

let container;
  kintone.events.on('app.record.index.show', (event) => {
    if (!container) {
      container = document.createElement('div');
      const header = kintone.app.getHeaderMenuSpaceElement();
      header.appendChild(container);
      // 1
    }
    // 2
    return event;
  });

header に対して更に何か処理を行う場合上記1の位置に記述することになると思いますが、

if 内の記述量を増やすと視認性が落ちるため、できれば上記2の位置に記述したいと思っています。

この場合、header の宣言を var で行うのがよいでしょうか?

あるいは、そもそも if の条件文を反対にして

let container;
kintone.events.on('app.record.index.show', (event) => {
  if (container) {
    return event;
  }
  container = document.createElement('div');
  const header = kintone.app.getHeaderMenuSpaceElement();
  header.appendChild(container);
// ここに記述
  return event;
});

というような形にするのがよいでしょうか? (あるいは更に他の方法が…?)

 

いわゆる「スマートな書き方」が分からないため、ご教示いただけますと幸いです!

3332 さん

お役に立てたようで何よりです。

早期 return はブロックを増やさずに見通しよく書ける一方、return で値を返す必要がある場合は同じコードを書くことになるので、バグが潜みやすくなりスマートではありません。

また、1つの関数の処理が数十行とかになると可読性が下がるので、処理ごとになるべく関数化することで見通しは良くなります。関数名は処理の内容が分かる名前にすると、コメントの代わりにもなります。

これらを踏まえて書くと以下のようなコードになります。

let textContainer;

kintone.events.on('app.record.index.show', (event) => {
  // スタンダードな書き方
  if (!textContainer) {
    createText();
  }

  // こういう書き方もできます①
if (!textContainer) createText();

  // こういう書き方もできます②
  textContainer || createText();

  return event;
});

function createText() {
  textContainer = document.createElement('div');
  const header = kintone.app.getHeaderMenuSpaceElement();
  header.appendChild(textContainer);
}

条件分岐さえしたくない、スコープ外に変数を作りたくない場合は、下記もありだと思います。

kintone.events.on('app.record.index.show', (event) => {
  createTextIfNeeded();

  return event;
});

function createTextIfNeeded() {
  const id = 'container';

  if (document.getElementById(id)) {
    return;
  }

  const container = document.createElement('div');
  container.id = id;
  const header = kintone.app.getHeaderMenuSpaceElement();
  header.appendChild(container);
}

最後に変数宣言についてですが、レガシーなブラウザ(IE11など)でなければ、var は使わずに基本は const、再代入の必要がある場合は let という使い分けをすると再宣言や再代入によるバグを防げるのでコードの堅牢性が高まります。 

以上になります。参考になれば幸いです。

川村さん

詳細にご教示くださりありがとうございました!非常に参考になりました!