Help us understand the problem. What is going on with this article?

Hyperstackでbrowser非表示のmodelの属性値をclipboardへコピー

More than 1 year has passed since last update.

親コンポーネントで#find_byで取得したmodelをparam に受け取って、リンククリック時にclipboardへコピーしたい。

  • TEXTAREAをマウントしてmodelの属性値をvalue(またはdefaultValue)に入れておいても、TEXTAREAを style で隠すと、element.select か copy がうまく動作しなかった。

  • リンククリック時に TEXTAREA要素を追加、select、copy、removeするのでは、属性値が取得できなかった。

解決法

catmandoさんから、コメント欄に解決法をいただきました。ありがとうございます!
@OneUser.name.loaded? を利用して、ロードが完了してからリンクが表示されるようにします。

class ClipTest < HyperComponent
  param :one_user

  render(DIV) do
# 'name'がロードされるまで空の文字列を表示する
    return '' unless @OneUser.name.loaded?

    A(href: '') { '名前をclip' }
      .on(:click) do |evt|
        evt.prevent_default
        copy_to_clipboard(@OneUser.name)
      end
  end

  def copy_to_clipboard(text_to_copy)
    supported = $$.document.queryCommandSupported('copy')
    puts("copy to clipboard is #{'not ' unless supported}supported.")
    return unless supported

    textarea = $$.document.createElement('textarea')
    copy_from = $$.document.body.appendChild(textarea)
    copy_from.textContent = text_to_copy

    puts("copy to clipboard : #{copy_from.textContent}")
    copy_from.select
    $$.document.execCommand('copy')
    copy_from.remove
  end
end

試行錯誤

textarea要素をマウントしておく方法では、display: 'none' で表示しないようにしておくと、select か copyがうまく動作しなかった。

class ClipTest < HyperComponent
  param :one_user

  render(DIV) do
    A(href: '') { '名前をclip' }
      .on(:click) do |evt|
        evt.prevent_default
        copy_to_clipboard(textarea_id)
      end

    TEXTAREA(id: textarea_id, 
             defaultValue: @OneUser.name,
             style: { display: 'none'})   # 隠してマウントしておく
  end

  def textarea_id
    "textarea-#{@OneUser.id}"
  end

  def copy_to_clipboard(element_id)
    supported = $$.document.queryCommandSupported('copy')
    puts("copy to clipboard is #{'not ' unless supported}supported.")
    return unless supported

    copy_from = $$.document.getElementById(element_id)
    puts("copy to clipboard : #{copy_from.textContent}")
    copy_from.select
    $$.document.execCommand('copy')
  end

これでリンクをクリックすると、puts で "copy to clipboard : <@OneUser.nameの値>" が正常にコンソールに出力されるのだが、クリップボードにはコピーされない。

TEXTAREAの styleを、{ display: 'block' }にした場合は、クリップボードへのコピーが正常にできた。

after_mount で属性をロードさせておいて、リンククリック時にTEXTAREA要素を追加。

class ClipTest < HyperComponent
  param :one_user

  after_mount do
    @OneUser.name
  end

  render(DIV) do
    A(href: '') { '名前をclip' }
      .on(:click) do |evt|
        evt.prevent_default
        copy_to_clipboard(@OneUser.name)
      end
  end

  def copy_to_clipboard(text_to_copy)
    supported = $$.document.queryCommandSupported('copy')
    puts("copy to clipboard is #{'not ' unless supported}supported.")
    return unless supported

    textarea = $$.document.createElement('textarea')
    copy_from = $$.document.body.appendChild(textarea)
    copy_from.textContent = text_to_copy

    puts("copy to clipboard : #{copy_from.textContent}")
    copy_from.select
    $$.document.execCommand('copy')
    copy_from.remove
  end
end

after_mount がないと、copy_to_clipboardの puts で "copy to clipboard : " とだけ出力された。引数のtext_to_copy に属性値が渡っていない。
この方法では、nameがロードされる前にリンクがクリックされた場合に問題が起きる。

KoyaChan
オープンソースの入り口に立って、のれんのすきまから覗き込んでいる初老のプログラマーです。 Visual C++ とwindbg をメインに、所属会社のパッケージソフトの開発とデバッグの業務を長く続けております。業務はqiitaへの投稿記事とは関係ありません。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away