2

Web開発とMVC4にかなり慣れていないので、同じ設計の問題に繰り返し遭遇し、MVC4の世界で正しい/サポートされている/などのソリューションが何であるかを誰かが教えてくれることを望んでいました。

基本的に、私はビューモデルkoolaidを飲んで、プロジェクト内のすべてのビューのビューモデルを持っています。そのほとんどは、単一ページアプリケーションの何かで動的に更新される部分的なサブビューです。ビューの生成/レンダリングはすべて順調に進み、ユーザーはクライアント側でいくつかの値を更新し、サーバーを更新します。

例として、それが単純なコンテナビューモデルであるとしましょう。

public class Data {
  public List<Prop> Props { get; set; }
}

public class Prop {
  public string Id { get; set; }
  public int Value { get; set; }
}

したがって、ユーザーがコンテナに新しい小道具を追加しているとしましょう。変更したオブジェクトをサーバーに戻すにはどうすればよいですか?

これまでのところ:サーバーがリアルタイムで同期していることが重要な場合は、サーバーで追加/更新するたびに電話をかけ、クライアントで同期を維持するか、サーバーに更新されたビューを返すようにすることができます。そのような単純なシナリオでは、すべてが順調です。

しかし、クライアントがオブジェクトを操作できるようにしたい場合(view / js / etcを介して)、サーバーで更新して送信するまで実際に更新する必要がない場合がよくあります。私が本当に望んでいるのは、レンダリングされたビューでオブジェクトを渡し、Javascriptを介してオブジェクトと対話し、すべてが完了したらオブジェクトをコントローラーに戻すことができるようにすることです。どうすればいいですか?(要点をつかむのに時間がかかったことをお詫びします!)

私が見た代替案:

--Quick &Dirty(RazorでviewmodelプロパティをJavaScriptにエンコード):これは確かにオブジェクトをクライアントのjavascriptに配置しますが、検証などを行わずにオブジェクト全体をクライアント側のhtmlにシリアル化するのはハックっぽいようです。 。(最終的には、それがオブジェクトの処理方法であることに気付きますが、MVC4オブジェクトの処理/解析全体をバイパスしているようです。)

--Upshot.Jsは、かつてはMSのサポートを約束していたようでしたが、死んだようです:Upshot.jsの現在の状況

--Breeze.js(http://www.breezejs.com/)は、そこを引き継ぐ試みのようですが、私の懸念は、それがかなり新しく、まだあまり広く採用されていないことです。

結局のところ、やや明白な代替案が欠けているように感じさせるのは、すべての要素がすでにMVC4に明確に組み込まれていることです。たとえば、フォームビューを使用する場合、フィールドはコントロールにデータバインドされ、フォームが送信されると、並列JSONオブジェクトが作成され、コントローラーに送信されてから、POCOViewModelオブジェクトに解析されます。これは基本的に私が探しているラウンドトリップです(ただし、完全なJSONオブジェクトをクライアント側に保持します)。それを処理するための「適切な」方法は何ですか?

4

2 に答える 2

2

Knockout はまさに私が探していたもの (または別のクライアント側の MV* フレームワーク) で、使い方がわかりませんでした。

@Mathletics と他のいくつかの SO ソリューションのおかげで、特に正しい方向に向けることができました

重要なのは、実際には ko.mapping ライブラリを使用することと、Json がサーバー側でモデルをエンコードまたはシリアル化することです。特に、このスクリプト ブロックは、強く型付けされた部分ビューでうまく機能しています。

<script type="text/javascript">
function viewModel() {
    // Additional Knockout Here    
};

var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
var mvcModel = ko.mapping.fromJSON(jsonModel);

var myViewModel = new viewModel();
var g = ko.mapping.fromJS(myViewModel, mvcModel);

ko.applyBindings(g);
</script>

これで、通常どおり Knockout を使用するための設定がすべて完了しました。

<div class="row">    
    <div class="span3">
        <h3>Bound Value:</h3>
        <span data-bind="text: PropertyName"></span>
    </div>
</div>

(これには、knockout.js、knockout.mapping.js、および Newtonsoft.Json が必要ですが、Json.Encode も同様に機能します。)

オブジェクトを戻すのは簡単です。オブジェクトを通常どおり更新し、それをコントローラーに戻すと、Json オブジェクトの準備ができており、サーバー側で POCO ビュー モデルとして戻されるように通常どおりに解析され、ラウンドが完了します。旅行。

于 2012-10-14T23:09:08.803 に答える
0

あなたの説明から、オブジェクトのコレクションをコントローラーに渡してからコレクションを更新する必要があることがわかります。コレクションにモデルをバインドすると、作業が簡単になります。

単一フィールドのコレクションにバインドする場合は簡単になりますが、オブジェクトのコレクションにバインドする場合は少し注意が必要です。シーケンシャルバインディングとノンシーケンシャルバインディングの 2 つのオプションがあります。

順次バインディング:

フォームが投稿されるコントローラー アクションは次のとおりです (HTTP POST アクション)。

public ActionResult UpdateProps(ICollection<Prop> Props) {
    return View(Props);
}

form method="post" action="/Home">    
    <input type="text" name="[0].Id" value="1001" />
    <input type="text" name="[0].Value" value="Prop1" />        

    <input type="text" name="[1].Id" value="" />
    <input type="text" name="[1].Value" value="NewProp" /> 

    <input type="submit" />
</form>

フォームが投稿されると、値は次のようになります

[0].Id=1001&[0].Value=Prop1&[1].Id=&[1].Value=NewProp

[0] と [1] のインデックスが表示されます。モデル バインダーは、インデックスに基づいてオブジェクトを適切にグループ化し、期待されるコレクションを取得します。投稿後、アクションは ICollection Props で 2 つのオブジェクトを取得します。1 つは ID 1001 で、もう 1 つは新しく追加されたものです。

ここで、新しいプロップを動的に追加する場合は、スクリプトを使用して適切にインデックスを付ける必要があることに気付くでしょう。または、それが難しい場合は、要素にインデックスを付ける代わりに、上記の形式で投稿できます。要素を解析し、スクリプトを使用してフォームを投稿する必要があります。データはインデックスで配置する必要があります。解析により、必要な要素のみを投稿できるという別の利点が得られます。つまり、すべてを投稿するのではなく、新しく追加または変更された要素のみを投稿できるため、ペイロードを節約できます。

一連の番号シーケンスの代わりに非シーケンシャル バインディングでは、インデックスは次のような一意の値です

[PropId1001].Id=1001&[PropId1001].Value=Prop1&[PropIdTemp233].Id=""&[PropIdTemp233].Value=NewProp

于 2012-10-14T15:45:47.403 に答える