7

これらは私のファイルです:

モデル

アプリ/モデル/バスケット.js:

export default DS.Model.extend({
  name: DS.attr('string'),
  house: DS.belongsTo('house', { async: true }),
  boxes: DS.hasMany('box', { async: true })
});

アプリ/モデル/box.js:

export default DS.Model.extend({
  qty: DS.attr('number'),
  basket: DS.belongsTo('basket'),
  cartLines: DS.hasMany('cart-line', { async: true })
});

app/models/cart-line.js:

export default DS.Model.extend({
  qty: DS.attr('number'),
  box: DS.belongsTo('box'),
  product: DS.belongsTo('product')
});

アプリ/モデル/product.js:

export default DS.Model.extend({
  name: DS.attr('string'),
  price: DS.attr('number')
});

ルート

app/routes/basket.js:

export default Ember.Route.extend({
  model(params) {
    return Ember.RSVP.hash({
      basket: this.store.findRecord('basket', params.basket_id),
      boxes: this.store.findAll('box'),
      products: this.store.findAll('product')
    });
  },
  setupController(controller, models) {
    controller.setProperties(models);
    }
});

コントローラー

app/controllers/basket.js:

export default Ember.Controller.extend({
  subTotal: Ember.computed('boxes.@each.cartLines', function () {
    return this.products.reduce((price, product) => {
      var total = price + product.get('price');
      return total;
    }, 0);
  })
});

質問:

私は初心者なので、勉強して間違いを犯しています。ごめん。

1)最初にルートに入ったときにEmber で関係をフィルターするのに最適な方法はどれですか? たとえば、アプリ内のすべてのボックスをロードしますboxes: this.store.findAll('box')。すべてのボックスを webapp にロードするのではなく、バスケットに 1 つだけロードする方法が必要です。バックエンドから直接「フィルター付きクエリ」が必要ですか?

更新された質問 2) 小計を計算するための最良の Ember の方法はどれですか? さて、以下のコードで、Ember は subTotal を提供しますが、promise の直後console.log(tot)です! なぜこれ?どうすれば約束を待つことができますか? 何をすべきかわかりません:

subTotal: Ember.computed('basket.boxes.@each.cartLines', function () {
  let count = 0;
  console.log('subTotal called: ', count);
  // It should be 0 ever
  count = count + 1;

  return this.get('basket.boxes').then(boxes => {
    boxes.forEach(box => {
      box.get('cartLines').then(cartLines => {
        cartLines.reduce(function (tot, value) {
          console.log('tot:', tot + value.get('product.price'));
          return tot + value.get('product.price');
        }, 0);
      });
    });
  });
});

テンプレート [object Object] で提供されるのは、hbs{{log subTotal}}とコンソールでも使用しているためです。

subTotal called:  0
ember.debug.js:10095 Class {__ember1476746185015: "ember802", __ember_meta__: Meta}
subTotal called:  0
ember.debug.js:10095 Class {__ember1476746185015: "ember934", __ember_meta__: Meta}
ember.debug.js:10095 Class {isFulfilled: true, __ember1476746185015: "ember934", __ember_meta__: Meta}
subTotal called:  0
ember.debug.js:10095 Class {__ember1476746185015: "ember1011", __ember_meta__: Meta}
ember.debug.js:10095 Class {isFulfilled: true, __ember1476746185015: "ember1011", __ember_meta__: Meta}
tot: 3.5
tot: 6
tot: 13.5
tot: 21
tot: 24.5
tot: 27
tot: 3.5
tot: 6
tot: 13.5
tot: 21
tot: 24.5
tot: 27
tot: 3.5
tot: 6
tot: 13.5
tot: 21
tot: 24.5
tot: 27

subTotal called: 0製品が 0 個でも 1 個でも 1000 個でも、3 回表示されるのはなぜですか。彼 は いつも 3 回 電話 を かけ ますsubTotal called: 0.なぜ?

promise で計算されたプロパティを使用するのは良いことですか?

3) 私はその関係のカプセル化で正しいですか?

更新された質問 2 :

今、私はこのコードを使用していますが、成功していません:

import Ember from 'ember';
import DS from 'ember-data';

export default Ember.Controller.extend({

  totalCount: Ember.computed('basket.boxes.@each.cartLines', function () {
    let total = 0;
    const promise = this.get('basket.boxes').then(boxes => {
      boxes.map(box => {
      // const trypromise = boxes.map(box => {
        console.log('box:', box);
        box.get('cartLines').then(cartLines => {
          console.log('cartLines:', cartLines);
          const cartLinesPromise = cartLines.map(cartLine => {
              console.log('cartLine:', cartLine);
              // return cartLine.get('qty');
              // return cartLine;
              // });
              return {
                qty: cartLine.get('qty'),
                price: cartLine.get('product.price')
              };
              //     return cartLines.map(cartLine => {
              //       console.log('cartLine:', cartLine);
              //       return cartLine.get('qty');
              //       //   return {
              //       //     qty: cartLine.get('qty'),
              //       //     price: cartLine.get('product.price')
              //       //   };
              //     });
            })
            // });
        return Ember.RSVP
          .all(cartLinesPromise)
          .then(cartLinesPromise => {
            console.log('cartLinesPromise:', cartLinesPromise);
            // cartLinesPromise.reduce((tot, price) => {
            //   console.log('tot:', tot);
            //   console.log('price:', price);
            //   console.log('tot+price:', tot + price);
            //   return tot + price, 0;
            // });

            return total = 10;
            // return total;
          })
        });

      });

      // return total;
    });

    return DS.PromiseObject.create({ promise });
  })

})

コメントは多くの試みのためのものです。

私が使用するテンプレートでは:

{{log 'HBS totalCount:' totalCount}}
{{log 'HBS totalCount.content:' totalCount.content}}
Total: {{totalCount.content}}

しかし、コンテンツpromiseがありnullます。

どこが間違っていますか?

間違っていreturnますか?

このコードは「有望」ですか?

4

2 に答える 2

1

特に質問が適切に構成され、熟考されている場合は、テクノロジーに慣れていないことは悪いことではありません。

1) Ember-Data の関係をフィルタリングする最良の方法はどれですか?

これは、多くの可能な結末を持つ複雑な質問です。

最も簡単な方法は、そのモデルについて尋ねることです。

かごで頼む

あなたのモデルを考えると、次のことができます:

model(params) {
  // we will return basket but make boxes ready
  return this.get('store').find('basket', params.basket_id).then(basket => {
    return basket.get('boxes').then(() => basket);
  });
}

しかし、これにはいくつかの制限と利点があります

  • バスケットでIDを送信する必要があります
  • 正常にするには、 coalesceFindRequestsを有効にする必要があります
  • ストアにないボックスのみをロードします

編集: you need to send ids with basketこれはbasket、ペイロードでボックスの識別を提供する必要があることを意味します。残り api の場合: {basket: {id: 1, boxes: [1,2,3], ...}. 次に、まだストアに読み込まれていない ID を確認し、ここで API に問い合わせます (ID 2 のボックスが既に読み込まれていると仮定します) /boxes?ids[]=1&ids[]=3

自問してみてください

model(params) {
  const store = this.get('store');
  const basket = params.basket_id;

  return RSVP.hash({
    model: store.find('basket', basket),
    boxes: store.query('box', {basket}),
  });
},
  • 一方、このアプローチは、バスケットがまだストアにない場合にのみバスケットのリクエストを送信しますが (以前と同じ)、常にボックスを照会します (気に入らない場合は、peekAll とフィルターを使用して、持っているかどうかを確認する必要があります)。それらのすべてまたはそのようなsmt)。
  • リクエストはシリアルではなくパラレルになるため、速度が向上する可能性があると考えてください。
  • Basket はボックスの ID を送信する必要もありません。
  • queryパラメータを変更することで、サーバー側のフィルタリングを行うことができます

編集: hasManyif you don't like it you would have to use peekAll and filter to check if you have all of themで実際に確認できます。

それらをサイドロードする

サーバーに 2 つのリクエストを送信する代わりに、ペイロードにボックスを追加するように API を作成できます。

バスケットのみをロードし、残りをテンプレートからロードします

最低限しかロードできず (バスケットのみをロードするように)、ember を続行してページをレンダリングします。basket.boxesプロパティにアクセスして取得していることがわかり ます。これだけでは見栄えが悪く、スピナーなどの追加作業が必要になります。しかし、これは起動と最初のレンダリング時間を短縮する方法の 1 つです。

2)小計を計算するための最良のEmberの方法はどれですか

非同期関係の 3 レベルの深さの何かの合計を計算したいのですが、それは簡単ではありません。まず、totalPrice の計算済みプロパティをバスケット モデル自体に配置することをお勧めします。計算されたプロパティは遅延評価されるため、パフォーマンスの低下はなく、これはモデルが提供できるものです。

ここに小さなスニペットがあります:

// basket.js
const {RSVP, computed} = Ember;

price: computed('boxes.@each.price', function() {
  const promise = this.get('boxes').then(boxes => {
    // Assuming box.get('price') is computed property like this
    // and returns promise because box must wait for cart lines to resolve.
    const prices = boxes.map(box => box.get('price'));

    return RSVP
      .all(prices)
      .then(prices => prices.reduce((carry, price) => carry + price, 0));
  });

  return PromiseObject.create({promise});
}),

レベルごとにこのようなものを書くか、非同期関係のいくつかを放棄する必要があります。計算されたプロパティの問題は、boxes.@each.cartLines全体的な価格を変更できるすべてのものをリッスンしないことです (たとえば、製品自体の価格の変更)。そのため、考えられるすべての変更を反映して更新するわけではありません。

いくつかの非同期関係を放棄することをお勧めします。たとえば、 request on/baskets/2は、すべてのボックス、cartLines、さらには製品をサイドロードできます。API がサイドローディングをサポートしていない場合は、ルートですべてをロードすることでそれを偽造できます (2 番目の例を使用する必要がありますasync: false。これにより、合計価格を計算するための計算されたプロパティがはるかに単純になり、サイドローディングの場合には、サーバーとクライアントの菓子へのストレスも軽減されます。

// basket.js
const {computed} = Ember;

boxes: DS.hasMany('box', {async: false}),

price: computed('boxes.@each.price', function() {
  return this.get('boxes').reduce(box => box.get('price'));
}),

更新と全体的な考えの後

1 つの関数ですべての合計を実行することが、実行可能、実行可能、または正気であるとは思いません。コールバック地獄またはその他の種類の地獄に行き着くでしょう。さらに、これはパフォーマンスのボトルネックにはなりません。

私はjsfiddleを作成しました。これは基本的に、上記のスニペットのより肉付けされたバージョンです。2 つの約束の深さである価格を適切に待機して伝播し、何かが変更されたときに更新する必要があることに注意してください (これもテストしていません)。

于 2016-10-14T01:02:09.710 に答える