13

以下に示すように、Meteor.startupを使用してfind()が入力されるリストがあり<li>ます。次に、data()を使用してこれらのすべてのデータ属性を取得し、<li>それをオブジェクトに入れてreturn / console.logを実行しようとしているので、機能するかどうかを確認できます。しかし、私はnull結果として得ています。

    Meteor.startup(function () {
    Template.messages.lists = function () {
        var allitems = lists.find();
        return allitems;
    };
    var map;
    map = new GMaps({
        div: '#map_canvas',
        lat: -12.043333,
        lng: -77.028333
    });
    var lat = map.getCenter().lat();
    var lng = map.getCenter().lng();
    map.addMarker({
        lat: lat,
        lng: lng,
        draggable: true,
        title: 'Test',
        dragend: function (e) {
            $('#lat').val(this.getPosition().lat());
            $('#lng').val(this.getPosition().lng());
        }
    });
    console.log(getMarkers());
});


function getMarkers() {
    var coordinates = {};
    coordinates = $('li.message').data();
    return coordinates;
}

私は自分のコンソールで同じことを直接試しましたが、それは機能します-オブジェクトを取り戻します-したがって、この関数が実行される前にDOMの準備ができていない/入力されていないと推測しています。

Meteor.startupとTemplate.mytemplate.renderedのようなものの違いを理解するのに苦労しています。この場合、それらのどれも私が望むように機能しないようですか?

DOMで何かを行うための正しい方法/場所は何ですか(トラバース、属性の取得、操作)?

編集

やりたいことをするためにコードが大きく変わったので、全部投稿しました。

Meteor.startup(function () {
  var map;
  map = new GMaps({
    div: '#map_canvas',
    lat: 50.853642,
    lng: 4.357452
  });
  Meteor.subscribe('AllMessages', function() {
    var allitems = lists.find().fetch();
    console.log(allitems);
    allitems.forEach(function(item) { 
      var lat = item.location.lat; 
      var lng = item.location.lng;
      console.log('latitude is: ' + lat);
      console.log('longitude is: ' + lng);
      map.addMarker({ 
        lat: lat, 
        lng: lng, 
        draggable: true, 
        title: 'Test', 
        dragend: function(e) { 
          $('#lat').val(this.getPosition().lat()); 
          $('#lng').val(this.getPosition().lng()); 
        } 
      }); 
    });
  });
});

上記のコードは、Meteor.Startup内に(GMaps.jsプラグインを使用して)新しいGoogleマップを作成し、ネストされたサブスクライブでコレクションからすべてのドキュメントをフェッチし、結果を取得して緯度と経度の値を取得し、さらに追加しますグーグルマップのマーカー...

編集2

このようにして、「map」変数をグローバル変数にしたので、.subscribeと.startupをネストする必要はありません。:

Meteor.subscribe('AllMessages', function() {
  var allitems = lists.find().fetch();
  console.log(allitems);
  allitems.forEach(function(item) { 
    var lat = item.location.lat; 
    var lng = item.location.lng;
    console.log('latitude is: ' + lat);
    console.log('longitude is: ' + lng);
    map.addMarker({ 
      lat: lat, 
      lng: lng, 
      draggable: true, 
      title: item.description, 
      dragend: function(e) { 
        $('#lat').val(this.getPosition().lat()); 
        $('#lng').val(this.getPosition().lng()); 
      } 
    }); 
  });
});

Meteor.startup(function () {
  map = new GMaps({
    div: '#map_canvas',
    lat: 50.853642,
    lng: 4.357452
  });
});

Template.messages.lists = function () {
  var allitems = lists.find().fetch();
  return allitems;
}
4

4 に答える 4

30

Meteor.startup

Meteor.startup()一度だけ実行され、クライアントとサーバーで実行されます。したがって、ブラウザがロードされ、最初のDOMの準備ができたとき、またはサーバーが起動したとき。Sohel Khalifaが言ったように、ここに初期化関数を配置します。この関数を起動する前にテンプレートを準備する必要があるため、ここでテンプレートを定義しないでください。

Template.myTemplate.onRendered(function(){...})

これは、meteorが終了してDOMをレンダリングしたときに実行されます。さらに、テンプレート内でHTMLが変更されるたびに実行されます。したがって、サブテンプレート内のリスト内の各アイテム/アイテムの変更/更新など、およびリストを使用すると、console.logが何かを返します。時々データを呼び出すときにnull/を返します(これについては説明します):undefined

これは、すべてのDOMの準備ができていることを意味しますか?いいえ!

これがあなたに少し問題を引き起こしているかもしれないものだと思います。Googleマップなどの外部APIを使用している場合でも、マップがレンダリングされる可能性があります。Meteorが必要なリアクティブ変数を使用してテンプレートのレンダリングを終了したTemplate.myTemplate.rendered()ことを意味します。したがって、Googleマップの準備ができているかどうかを確認するには、GoogleマップAPIに接続する必要があります。この質問を見てください

Meteor.subscribeを使用する

使用中にnull/を取得する可能性がある理由は、これが流星が通常データをテンプレートにレンダリングするプロセスであるためですundefinedrendered

基本的console.log(getMarkers());に、サブスクリプションが完了する前に電話をかけているため、null/undefined

Meteorは、この要約されたプロセスをテンプレートとリアクティブデータで使用します。

  1. データとレンダリングを使用せずにテンプレートを作成する-この段階ではまだデータはありません
  2. コレクション内のデータをサーバーに要求する
  3. 新しいデータでテンプレートを再構築してレンダリングする

したがって、プロセス1)で非常に短時間の場合、まだデータがないため、null(コードなどで)最初のレンダリングで取得する可能性があります。これを乗り越えるMeteor.subscribeには、すべてのデータがサーバーからダウンロードされたときに実行されるのコールバックを使用する必要があります。

Meteor.subscribe("lists", function() {
    //Callback fired when data received
});

注:これを使用する前に、パッケージを削除する必要があるため、サブスクリプションの使用に関するドキュメントを読み、サーバー上で対応する機能を作成する必要があります。これは退屈に思えるかもしれませんが、とにかくユーザーに独自のリストを提供したり、ある種のセキュリティを実装したりするためにそれを行うことになるかもしれません。autopublishMeteor.publish

コードの推奨される編集:

適切な場所でDOMトラバースを実行していますが、Template.mytemplate.onRendered(function()..マップの描画が終了したときにキャプチャするには、GoogleマップのAPIにフックする必要もあります。また、 /Meteor.subscribeを取得するのではなく、タイミングを正しく取得するために使用する必要があります。nullundefined

Meteor.startupは、最初のDOMの準備ができた後(最初は最初ですが、リアクティブ変数またはルーターによって変更される前)に起動されるため、テンプレートヘルパーを配置しますMeteor.isClientが、配置しないでください。テンプレート定義は、に実行する必要があります。この段階。Meteor.startup

于 2013-03-09T21:21:02.917 に答える
2

結果として返される理由nullは、に配置したためですMeteor.startup()。実際には、サーバーからデータがロードされる前に実行されます。したがって、lists.find()nullを返します。

これMeteor.startup()は、グローバル変数、相対セッションを初期化し、サーバーからの主要なデータの束をサブスクライブするための場所です。そこに書き込んだものはすべて、クライアントの起動直後に一度実行されます。

これTemplate.myTemplate.rendered()は、対応するデータが変更されるたびに実行されるmeteorによって提供される特別なヘルパーであり、主に、そのテンプレートに含まれる属性の取得またはDOM要素の操作に使用されます。

したがって、ヘルパーコードを共有isClient()領域の外に配置します。また、.rendered()ヘルパーを使用してDOMをトラバースし、DOM要素の属性を取得または操作します。

于 2013-03-09T17:41:13.927 に答える
2

詳細な回答をありがとうAkshat)

Meteor.subscribeを使用するより複雑なケースがあり、DBからの画像を含むテンプレートがあります。だから私は2つのコレクション画像とニュースからのデータを待つ必要があります(他のすべてのデータはここにあります)。

この方法でDOMを準備します。

imageIsLoaded = new Promise(function(resolve){
    Meteor.subscribe('images',function(){
        resolve()
    });
});

newsIsLoaded = new Promise(function(resolve){
    Meteor.subscribe('news',function(){
        resolve()
    });
});


Template.newsList.onRendered(function(){
    Promise.all([imageIsLoaded, newsIsLoaded]).then(function() {
        // DOM IS READY!!!
        newsServices.masonryInit();
    })
});

テンプレート構造:

<template name="newsList">
         {{#each news}}
            {{> news_item}}
        {{/each}}
</template>
于 2016-06-02T14:46:08.307 に答える
1

これを行う最良の方法は、コードをTemplate.x.rendered()に配置し、Sessionリアクティブ変数を使用して、コードが実行されたかどうかを追跡することです。たとえば、次のように行うことができます。

Template.x.rendered = function () {
  if (Session.get('doneMarkers') == null) {
    // Do your stuff
    if (getMarkers() != null) {
      Session.set('doneMarkers', 'yes');
    }
  }
});

function getMarkers() {
  var coordinates = {};
  coordinates = $('li.message').data();
  return coordinates;
}

コードのその部分を再実行したい場合は、以下を呼び出すだけです。

Session.set('doneMarkers', null);
于 2013-03-09T20:59:53.557 に答える