9

コレクションからアイテム名のリストを単純な配列として取得して、ユーザー入力のオートコンプリートや重複のチェックなどに使用したいと考えています。データの変更が配列に反映されるように、このリストをリアクティブにしたいと考えています。Meteorのドキュメントに基づいて、次のことを試しました。

    setReactiveArray = (objName, Collection, field) ->
        update = ->
          context = new Meteor.deps.Context()
          context.on_invalidate update
          context.run -> 
            list = Collection.find({},{field: 1}).fetch()
            myapp[objName] = _(list).pluck field
        update()

    Meteor.startup ->
        if not app.items?
            setReactiveArray('items', Items, 'name')

    #set autocomplete using the array
    Template.myForm.set_typeahead =  ->
       Meteor.defer ->
        $('[name="item"]').typeahead {source: app.items}    

このコードは機能しているように見えますが、アプリの読み込み時間が長くなります (dev/localhost での読み込みに 5 ~ 10 秒かかりますが、このコードを使用しない場合は約 1 秒かかります)。私は何か間違ったことをしていますか?これを達成するためのより良い方法はありますか?

4

4 に答える 4

6

を使用できるはずですItems.find({},{name: 1}).fetch()。これはアイテムの配列を返し、リアクティブであるため、リアクティブコンテキストで呼び出されている限り、クエリ結果が変更されるたびにその囲み関数を再実行します。

ヘルパーの場合、Template.myForm.set_typeaheadヘルパー自体の内部でそのクエリを呼び出し、結果をローカル変数に格納してから、Meteor.deferその変数を参照する関数を使用して呼び出すことができます。そうしないと、クエリが呼び出されたときにリアクティブコンテキスト内にあるかどうかわかりません。

于 2012-12-17T08:18:30.403 に答える
5

編集:以下のコードは壊れやすいため、テストしやすいようにコンテキストに入れるために更新しました。注意事項も追加しました。ほとんどの場合、@zorlak または @englandpost のメソッドを使用することをお勧めします (以下を参照)。


まず、誰も答えなかった私の古い質問を掘り下げてくれた @zorlak に敬意を表します。@David Wihl から収集したいくつかの洞察でこれを解決し、独自のソリューションを投稿します。他の人が検討する機会があるまで、正しい答えを選択するのを保留します.

@zorlak の回答は、単一フィールドのオートコンプリートの問題を解決しますが、質問に記載されているように、リアクティブに更新される配列を探していました。オートコンプリートは、その使用目的の一例にすぎません。この配列を持つ利点は、(テンプレート ヘルパーだけでなく) どこでも使用できることと、クエリを再実行する必要なくコード内で複数回使用できることです (そして、_.pluck()クエリを配列に減らします)。 . 私の場合、この配列は複数のオートコンプリート フィールドと、検証やその他の場所で終了します。私が提示している利点は、ほとんどの Meteor アプリでは重要ではない可能性があります (コメントを残してください) が、これは私にとって利点のように思えます。

配列をリアクティブにするには、単純にMeteor.autorun()コールバック内に構築します。これは、ターゲット コレクションが変更されるたびに再実行されます (ただし、その場合に限り、繰り返しのクエリを回避します)。これが私が求めていた重要な洞察でした。また、コールバックを使用することは、私が質問で使用したテンプレート ヘルパーTemplate.rendered()よりもクリーンでハックが少なくなります。set_typeahead以下のコードは、underscore.js_.pluck()を使用してコレクションから配列を抽出し、Twitter ブートストラップ$.typeahead()を使用してオートコンプリートを作成します。

更新されたコードmeteor create: ストックd テスト環境でこれを試すことができるように、コードを編集しました。HTML には<input id="typeahead" />、'hello' テンプレートの行が必要です。コンソールでグローバルとして使用できるようにするため@Items@記号があります ( Meteor 0.6.0 でファイルレベルの変数スコープが追加されました)。そうすれば、コンソールに などの新しい項目を入力できますが、コードが機能するためには必要ありません。スタンドアロンでの使用に必要なその他の変更は、typeahead 関数がソースを関数 ( ) に設定するようになったことです。これにより、レンダリング時に設定されるのではなく、アクティブ化されたときにクエリが実行され、 への変更を利用できるようになります。ItemsItems.insert({name: "joe"})@->itemsitems

@Items = new Meteor.Collection("items")
items = {}

if Meteor.isClient
  Meteor.startup ->
    Meteor.autorun ->
      items = _(Items.find().fetch()).pluck "name"
      console.log items  #first result will be empty - see caution below

  Template.hello.rendered = ->
    $('#typeahead').typeahead {source: -> _(Items.find().fetch()).pluck "name"}

注意!作成した配列自体は、リアクティブ データ ソースではありません。返される関数に typeaheadsource:を設定する必要がある理由は、Meteor が最初に起動したときに、Minimongo がサーバーからデータを取得する前にコードが実行され、空の配列に設定されるためです。Minimongo はそのデータを受け取り、更新されます。コンソールを開いた状態で上記のコードを実行すると、このプロセスを確認できます。データが保存されている場合は、2 回ログに記録されます。 ->itemsitemsitemsconsole.log items

Template.x.rendered()呼び出しは反応性コンテキストを設定しないため、反応性要素の変更により再トリガーされません (これを確認するには、デバッガーでコードを一時停止して調べDeps.currentComputationますnull。反応要素への影響は無視されます)。itemsしかし、テンプレートとヘルパーも変更に反応しないことを知って驚くかもしれません。#each繰り返し処理をitems行うために使用するテンプレートは空でレンダリングされ、再レンダリングされません。リアクティブ ソースとして機能させることができます (最も簡単な方法は、結果を で保存するSession.set()、自分で行うことができます)。)、しかし、可能な限り実行する必要のない非常に高価な計算を行っている場合を除き、@zorlak または @englandpost の方法を使用する方が適切です。アプリがデータベースに繰り返しクエリを実行するのはコストがかかるように思えるかもしれませんが、Minimongo はネットワークを回避してデー​​タをローカルにキャッシュしているため、非常に高速です。したがって、ほとんどの状況では、単に使用する方が良いです

  Template.hello.rendered = ->
    $('#typeahead').typeahead {source: -> _(Items.find().fetch()).pluck "name"}

アプリが本当に動かなくなっていることが判明しない限り。

于 2012-12-21T20:16:31.867 に答える
1

実際には、サーバーにクエリを実行する代わりにクライアント側のコードを使用して、オートコンプリートの問題にまったく異なる方法でアプローチすることになりました。Meteor のデータ モデルでは、カスタム レンダリング リストを使用した複数ルールの高速検索が可能であるため、これは優れていると思います。

https://github.com/mizzao/meteor-autocomplete

オンラインユーザー@は緑色で表示されます。

ここに画像の説明を入力

同じ行で、メタデータとブートストラップ アイコンを使用して別のものをオートコンプリートします。

ここに画像の説明を入力

フォーク、プル、改善してください!

于 2013-09-22T22:10:11.923 に答える
1

これがブートストラップの先行入力に対する私の簡単な解決策です

クライアント側:

Template.items.rendered = ->
  $("input#item").typeahead
    source: (query, process) ->
      subscription = Meteor.subscribe "autocompleteItems", query, ->
        process _(Items.find().fetch()).pluck("name")
      subscription.stop() # here may be a bit different logic,
      # such as keeping all opened subsriptions until autocomplete
      # will be successfully completed and so on
      items: 5

サーバー側:

Meteor.publish "autocompleteItems", (query) ->
  Items.find
    name: new RegExp(query, "i"),
      fields: { name: 1 },
      limit: 5
于 2013-01-28T22:30:26.523 に答える