24

mvcモデルをknockoutjsに渡す方法についてグーグルで調べましたが、2つの方法があるようです:

  • @Html.Raw(Json.Encode(Model)) の使用
  • $.get または $.ajax の使用

mvcモデルをknockoutjsに渡すベストプラクティスはどれですか? 要件ごとであることはわかっていますが、 @Html.Raw メソッドよりも $.get を使用する方がクリーンなようです。

4

8 に答える 8

23

私はいくつかのアプローチをうまく使用しました。

強く型付けされたRazorビューでは、他のHTMLと同じようにJavaScript ViewModelオブジェクトを記述し、モデル要素を挿入することができます。RazorとJSはVisualStudioとIntellisenseと一緒にうまく機能しないため、これは扱いにくいと思いますが、赤い波線がたくさんある場合でも、結果のコードは正常に機能します。

<script type="text/javascript">

var data = [
    @for (int i=0; i < Model.Packages.Count; i++)
    {
        var package = Model.Packages[i];
        <text>{Id: ko.observable(package.Id),
               Name: ko.observable(package.Name)
              }</text>
    }

    var viewModel = {
        var packages = ko.observableArray(data);
        // more code
    }

    ko.applyBindings(viewModel);
</script>

このコードは、モデルの複雑さによっては、急いで醜くなる可能性があります。前述のように、Html.Raw()を使用してモデルオブジェクトをJSONにシリアル化することもできます。そのルートに行く場合は、それを使用して、KOマッピングライブラリを使用してKnockoutViewModelを構築できます。

<script type="text/javascript">
    var data = @Html.Raw(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model));
    var viewModel = ko.mapping.fromJS(data);
    ko.applyBindings(viewModel);
</script>

これは最初のオプションほど厄介ではありませんが、私はこの方法であまりにも多くの制御をあきらめているように感じます。これは、KOViewModelがMVCViewModelの構造と非常に緊密に結合されていることを意味します。これは、必要な場合と不要な場合があります。言うまでもなく、これが機能するためには、JavaScriptがcshtmlページにある必要がありますが、これは本当に好きではありません。最後に、これらのアプローチは両方とも純粋にサーバー側です。SPIなどのより応答性の高いWebページの場合は、クライアント側でより多くのことを実行する必要があります。

私の好みは、JavaScript自体からクライアント側を呼び出す$.getJSONを使用することです。その時点で、手動でローリングするか、マッピングライブラリを使用して、戻りデータをViewModelに処理できます。MVCコントローラーのアクションにコールバックする場合は、アクションに(ActionResultではなく)JsonResultタイプを返すようにします。(ContentResultでも同様のことができます)新しいMVC4 WebAPIを使用できる場合、これらのコントローラーはデフォルトでJSONを返します。

于 2012-07-24T18:07:16.717 に答える
8

@ Html.Raw(Json.Encode(Model))は、実際のページダウンロードの一部としてデータを送信する場合に使用されます。これにより、ページがユーザーにレンダリングされるまでに時間がかかる可能性がありますが、レンダリングされると、すべての準備が整います。

$.getまたは$.ajaxは、代わりにページのレンダリング中にデータを取得します。これにより、別の呼び出しが作成され、レンダリング後にページが更新されます。

どちらを使用するかは、ページのレイアウト、最初にすべてのデータが必要かどうか、データの取得とページのレンダリングにかかる​​時間によって異なります。

于 2012-07-24T18:15:30.200 に答える
7

私のアプローチ:

  • ビュー モデルは独自の JS ファイルに記述され、サーバー側のコード生成はありません
  • ビュー モデルは $.get または $.ajax を介してデータを読み込みます
  • ビュー モデルを作成するときにビューがオブジェクトを渡します。このオブジェクトには、サーバー側で生成されたすべての URL が含まれます。

例:

function MyViewModel(urls) {
    var self = this;
    self.isLoading = ko.observable(true);
    self.items = ko.observableArray();
    self.loadData = function() {
        $.get(urls.load, function(data) {
                // Process data and push into our items array
                self.isLoading(false);
            });
    }
}

var vm = new MyViewModel({
        load: '@Url.Action("GetData", "MyItemController")'
    });

$(function() {
    ko.applyBindings(vm);
    viewModel.loadData();
});

これは、データに対する追加の AJAX 呼び出しがあることを意味しますが、IMO ユーザーはそのデータ != UI に気付き始めています。利点は、実際のデータ アクセスが関係しないため、UI をすばやく提供できることです。データベースやデータの量などによっては、データのロードに時間がかかる場合があります。また、私のコードでは、問題が非常に明確に分離されます。

于 2012-08-07T22:15:27.773 に答える
3

@ Html.Rawを使用するのは、ノックアウトUIが生成されるまでユーザーがページ上で実行できる有用なことは何もないためです。また、JSONをページに書き込むことによる余分な初期ダウンロードによる潜在的な些細なタイムラグは、ユーザーによって相殺されます。 UIが構築される前に不安な遅延が発生します。最初のビューモデルを構築するために使用されるJSONがページに直接存在することに、まったく問題はありません。

私が効率を上げるのは、MVCコントローラーからダウンロードした別の動的スクリプトで選択オプション(製品のリストなど)などの再利用可能な参照データを取得し、ブラウザーによってキャッシュすることです。そうすれば、ビューモデル間で再利用でき、ビューモデルは選択したアイテムの値を保存するだけで済みます。

于 2012-07-25T04:14:06.237 に答える
3

私がしているのは Html.Raw で、その js オブジェクトをノックアウト js モデルに渡します。このようなもの:

//I'm using Newtonsoft library to serialize the objects
@{
    var jsModel = Newtonsoft.Json.JsonConvert.SerializeObject(Model);
}

<script type="text/javascript">
var model = @Html.Raw(jsModel);

var vm = new MyKnockoutModel(model);
ko.applyBindings(vm);

var MyKnockoutModel = function(model) {
    var self = this;
    this.Id = ko.observable(model.Id);
    this.Name = ko.observable(model.Name);
    this.Array1 = ko.observableArray(model.Array1);
}

</script>

それが私がすることです。

于 2013-05-27T13:22:41.130 に答える
2

あなたが言うように、それはほとんど要件ごとの基準です。

「1ページアプリケーション」を実行している場合は、多くの$.getおよび$.ajax呼び出しを実行します。単一ページをレンダリングするだけの場合は、モデルをモデルに配置する方が速い場合があります。 HTML、サーバーへの余分なリクエストを保存します。

また、サーバー側で必要なコードの量にもよりますが、アプリケーションでAPIが必要な場合は、APIを再利用して、$。getと$ .ajaxの呼び出しを行う傾向があります。そうでない場合は、モデルをHtmlに配置します。

于 2012-07-24T13:15:33.377 に答える
0

古い質問ですが、再利用可能な方法で、モデル データを KO ビュー モデルに渡すためのきちんとした解決策があると思います。注意、require.js も使用しています。

.NET で HtmlHelper 拡張メソッドを追加します。

using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace PROJECT.YOUR.EXTENSIONS.NAMESPACE {

    public static class HtmlHelperJavascriptExtensions {

        public static IHtmlString Serialize(this HtmlHelper helper, object obj) {
            return helper.Raw(new JavaScriptSerializer().Serialize(obj));
        }
    }
}

部分ビュー、KnockoutJsBinderPartial を追加します (私は aspx を使用する必要がありました)。

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<PROJECT.Views.Shared.KnockoutJsBinderViewData>" %>
<%@ Import Namespace="PROJECT.YOUR.EXTENSIONS.NAMESPACE" %>

<script type="text/javascript">
    require(["Path/To/KnockoutJs", "<%= Model.ViewModelPath %>"], function (ko, ViewModel) {
        ko.applyBindings(new ViewModel(<%= Html.Serialize(Model.InnerModel) %>));
    });
</script>

そのビューによって参照されるモデルは次のとおりです。

namespace PROJECT.Views.Shared {

    public class KnockoutJsBinderViewData {

        public object InnerModel { get; private set; }

        public string ViewModelPath { get; private set; }

        public KnockoutJsBinderViewData(object innerModel, string viewModelPath) {
            InnerModel = innerModel;
            ViewModelPath = viewModelPath;
        }
    }
}

.NET モデルをノックアウト ビュー モデルに結び付けるために必要なことは、次のとおりです。

<% Html.RenderPartial(
   "~/Views/Shared/KnockoutJsBinderPartial.ascx",
   new PROJECT.Views.Shared.KnockoutJsBinderViewData(
        Model, // The model from your strongly typed MVC view
        "Path/To/Knockout/ViewModel")); // The path to the Javascript file containing your view model
%>

ビュー モデルを含む Javascript ファイルは ko.applyBindings を呼び出すべきではなく、ビュー モデルのコンストラクター関数を返す必要があることに注意してください。コンストラクターは、1 つの引数 (モデルの JSON データ) を取る必要があります。

于 2014-12-09T23:55:14.887 に答える