0

これを行う方法について頭を悩ませることはできません。Julie Lerman の "BreezyDevices" ソリューションから学び始め、彼女の JavaScript ビューモデルをベースとして使用しました。

私は持っている:

//properties and methods to expose via this class
var vm = {
    game: ko.observableArray([]),
    save: function () {
        dataservice.saveChanges();
    },
    reset: function () { dataservice.reset(getAllGames) },

};

ビューモデルの上部にあり、これにより、各ゲームが配列で返されます。すべて正常に動作します。「Games」には、プロパティとして「ourscore」と「irscore」を含む「Sets」という配列を返す関連データがあります。

私のhtmlページでは、「ゲーム」エンティティの一部として返される具体的なデータベースプロパティをバインドしたいのですが、各セットスコアをループするjavascript関数に基づいて計算される各ゲームの「結果」プロパティも作成したいと考えています。それに応じて値を返します。

私はそよ風の「Todo」ソリューションでレイアウトを使用してみましたが、これを上記のコードのすぐ下に設定しました。

initVm();

function initVm() {
    addComputeds();
}

function addComputeds() {
    vm.result = ko.computed(function () {
        var ourSets = getResult().ourSets;
        var theirSets = getResult().theirSets;

        if (ourSets == 0 && theirSets == 0) {
            return "No Result";
        }
        return (ourSets > theirSets ? "Won " : "Lost ") + "<b>" + ourSets.toString + "</b>-" + theirSets.ToString;
    });
}


function getResult() {
    var ourSets = 0;
    var theirSets = 0;

    vm.game().forEach(function (game) {
        for (var gs in game.Sets) {
            if (gs.ourScore > gs.theirScore) {
                ourSets +=1;
            }
            else {
                theirSets +=1;
            }               
        }
    });

    return {
        ourSets: ourSets,
        theirSets: theirSets
    };
}

しかし、それは、各ゲームエンティティではなく、ビューモデル (vm) に「結果」を追加するように思えますか? また、コードを実行してもエラーは発生しませんが、表示できる場所に「結果」プロパティが作成されず、機能していないように見えます。

ここに追加してもう一度見ると、ゲームの配列ではなく、特定のゲームエンティティごとに処理して各結果を計算する必要があるため、間違っていることがわかりますvm.result) ですが、私はこれに慣れていないため、個々のゲーム エンティティに対処する方法を理解できません。私の .net コーディングの頭脳は、ループ内の各ゲーム エンティティを関数に渡して、そのゲームの結果を返すようにしますが、それがそよ風/ノックアウトでもどのように機能するかはわかりません。

私はどこでもグーグルで検索しましたが、私の要件に関連する例が見つからないようですので、いくつかのポインタをいただければ幸いです!


@BeaverProj

これが発生する main.js ファイルがあります。

(function (root) {
    var app = root.app;

    app.logger.info('Please wait... data loading');

    ko.applyBindings(app.gameViewModel, $("content").get(0));

    $(".view").css({ display: 'block' });
}(window));

トップセクションをこれに編集しました:

var vm = {
    game: ko.observableArray([]),
    save: function () {
        dataservice.saveChanges();
    },
    reset: function () { dataservice.reset(getAllGames) },
    result: ko.computed(function () {
        var gameRes = getResult();
        var ourSets = gameRes.ourSets;
        var theirSets = gameRes.theirSets;

        if (ourSets == 0 && theirSets == 0) {
            return "No Result";
        }
        return (ourSets > theirSets ? "Won " : "Lost ") + "<b>" + ourSets + "</b>-" + theirSets;
        })
};

「getResult」は、「vm...」ではなく「app.gameViewModel.game().forEach(function (Game) {」を参照するようになりました

前と同じ - エラーはありませんが、結果もありません。私はまだ「ゲーム」の配列を取得していますが、他には何もありません。上記のビューモデルはまだ私には間違っているようです...「結果」はvmではなくゲームエンティティ(vm.game)に添付する必要があります-現在、これはvm.resultを提供し、ゲームごとに結果があります(したがってvm. game.result)、ゲームの配列ごとではありません。これが、そよ風を介してエンティティを拡張する必要があるかどうか疑問に思っている理由です。私は通常の JavaScript でこれを行うことができますが、そよ風またはノックアウトはこれをはるかに簡単に行うことができるように思われますか?

4

4 に答える 4

0

汗だくにしないでください。探索を続けます。私たちは皆、学んでいます。

これを ViewModel (VM) に配置した方が良いのか、エンティティに配置した方が良いのかわかりません。本質的な正解はありません。

エンティティでそれが必要であると仮定しましょう (Breeze の観点からすると、より興味深いからです)。次の質問: 観察可能にする必要がありますか?

これは計算の単純なスタンドアロンの結果であり、表示目的でのみ使用されます。結果に影響を与えるページでは何も変更できません。すでに発生しています。」これは、観察可能である必要がないことを示唆しているため、計算されたKO。あなたの最新のソリューションは、それをプロパティとして提示していません。VM の何かが を呼び出していると思いますgetResult()

これにより、カスタム コンストラクターを登録しgetResult、そのコンストラクターのプロトタイプを作成する方がよいのではないかと思います。

var ゲーム = 関数 () { }

Game.prototype.getResult = 関数 () {
  var 私たち = 0;
  var theirs = 0;
  this.sets().forEach(関数 (s) {
    (s.ourScore() > s.theirScore()) ? 私たちの += 1 : 彼らの += 1;
  });
  return (私たち || 彼らのもの) ?
      (私たち > ​​彼ら ? "勝った" : "失われた ") + 私たち + "-" + 彼ら:
      "検索結果はありません";
}

store.registerEntityTypeCtor("ゲーム", ゲーム); // ctor あり、イニシャライザなし

一方、スコアが変化する可能性があり、そのように画面を更新したい場合は、ロジックをresultsKO 計算に移動することをお勧めします。およびオブザーバブルは、計算されたものを最新に保つ必要がourScoreあります。私はここで大声で考えています。試したことはありません。theirScoreresults

ctor ではなくイニシャライザresultsで計算されたものを定義します。なんで?KO オブザーバブルは、プロトタイプではなく、インスタンスにアタッチする必要があるためです。ctor 内で定義した場合、Breeze はシリアル化して追跡を変更しようとする可能性があります。イニシャライザのエンティティに追加することをお勧めします。Breeze は、初期化子によって追加されたエンティティ メンバーを無視します。

さらに考えてみるとgetResult、プロトタイプにあるメソッドを保持し、計算された ko を追加する初期化子を作成する可能性があります...そのように (警告: テストされていません):

関数 gameInitializer(ゲーム) {
   game.results = ko.computed(function() { return game.getResults();});
}

store.registerEntityTypeCtor("ゲーム", ゲーム, gameInitializer);

そして今、重大な点として、このロジックは dataservice にある必要がありますか?

あなたが自分自身を述べているまさにその理由で、私はそれを私のデータサービスに入れませんこの種のロジックは、モデルに固有の懸念を表しており、データ アクセスの管理とは何の関係もありません。デモのデータサービスですべてをまとめても問題ありません。「実際の」コードでは、それをmodel.jsコンポーネント ( GameViewModel コンポーネントではなく Model コンポーネントと考えます) に分解し、そのスクリプトを dataservice.js と viewmodel.js スクリプト タグの間にロードします。

于 2013-01-22T05:41:34.190 に答える
0

わかりましたので、多くのことをいじった後、私はいくつかの進歩を遂げました。申し訳ありませんウォード (これを読んだ場合) - あなたのドキュメンテーションは経験豊富なコーダーにとっては素晴らしいかもしれませんが、初心者にとっては良いものではありません!)

dataservice.js のトップは次のようになりました。

var manager = new breeze.EntityManager(serviceName);
var store = manager.metadataStore;

var Game = function () {
    //this.result = "Won 3-2";

};

var gameInitializer = function (game) {
    //game.result = "Won 3-2";
    game.result = function () {
        return getResult(game);
    }();
 };

store.registerEntityTypeCtor("Game", Game, gameInitializer);

および getResult 関数:

function getResult(game) {
    var ourSets = 0;
    var theirSets = 0;

    game.Sets().forEach(function (gs) {
        if (gs.ourScore() > gs.theirScore()) {
            ourSets += 1;
        }
        else {
            theirSets += 1;
        }
    }
    );
    if (ourSets == 0 && theirSets == 0) {
                return "No Result";
    }
    else {
            return (ourSets > theirSets ? "Won " : "Lost ") + ourSets + "-" + theirSets;
    }
}

これは、明らかに、「構築後のイニシャライザ」として簡単に知られており、この場合、結果に対して何もする必要がないため、私のニーズに適したソリューションのようです。これは、計算の単純なスタンドアロンの結果であり、表示目的でのみ使用されます。結果に影響を与えるような変更をページ上で行うことはできません。変更は既に行われています。

私がまだわからないのは、これがこれを行うための最も(または唯一の)方法であるかどうか、または代わりにノックアウトまたは標準のjavascriptで同様の結果を達成できるかどうかです. ブリーズ内でそれを行うと、関連する「セット」エンティティを公開するために必要なゲーム エンティティの受け渡しを処理するように見えます。かっこが追加されたプロパティを参照するように注意する必要がありました。そうしないと、すべて失敗しました。

ただし、データサービスにモデル固有のコンストラクター、初期化子、および関数が散らばっているという考えは好きではありません。私の考えでは、私が行ったことのほとんどは、現在のように一般的な「dataservice.js」ファイルではなく、「vm.game.js」ファイルに属しています。

ここで、コードをシフトしようとします。参考書を作るのに時間がかかるかもしれません!

于 2013-01-21T23:07:36.887 に答える
0

構築後のイニシャライザは、ko マッピング プラグイン doc'd @ http://knockoutjs.com/documentation/plugins-mapping.htmlを使用するというこの問題に対する答えと非常によく似ています。

マッピング構成を使用して作成ハンドラーを追加し、必要な計算結果オブザーバブルを追加します。何かのようなもの

var mapping = {
  game : {
    create : function(options) {
            var game = options.data;
            game.results = ko.computed( function(){ 
              //your result sets calc here
            }  );

            return game;
        }
  }
}

さらに良いのは、独自の GameVM タイプを定義してそこに配置することです。

function GameVM( GameData )
{
    var self = this;
    this.Sets = ko.mapping.fromJS( GameData.Sets );
    this.Results = ko.computed( function(){
         self.Sets()...
    } );

}

とのマッピング

 var mapping = {
      game : {
        create : function(options) {
               return new GameVM( options.data );
      }
    }

これはよりクリーンで、テストする単位が小さいため、ゲーム VM をよりテストしやすくします。

マッピングのドキュメントをチェックアウトして、カスタム更新コールバックを介した reset() 呼び出しにどのように役立つかを実際に確認してください。

于 2013-01-22T05:42:55.323 に答える
0

いくつかのこと:

  • ビューモデル定義内で宣言された結果計算関数が必要になることは間違いありません。リセット機能の下に置くだけです。

  • 共有したコードでは、ビュー モデルを初期化していないか、knockout.js と共有していません。次のような場所に電話する必要があります。

    var gameViewModel = new vm(); ko.applyBindings(gameViewModel);

  • その変更の後、getResult() メソッドで、vm 変数 (クラス定義) の代わりに gameViewModel (インスタンス) を参照します。

  • あまりにも多くの作業を行うかどうかに影響を与えるべきではない最後の 1 つのことは、計算された結果で getResult() を 1 回だけ呼び出して、戻り値を変数に割り当てる必要があることです。そうしないと、2 回計算することになり、リソースが無駄になり、技術的には呼び出し間で変更される可能性があります。

于 2013-01-20T15:22:14.743 に答える