web-dev-qa-db-ja.com

MvcモデルをKnockoutJSに渡す際のベストプラクティス

私はmvcモデルをknockoutjsに渡す方法をググったところ、2つの方法があるようです:

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

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

24
gnaungayan

私はいくつかのアプローチを成功させてきました。

強く型付けされたRazorビューでは、他のHTMLと同じようにJavaScript ViewModelオブジェクトを記述して、モデル要素を挿入します。 RazorとJSはVisual Studioや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マッピングライブラリを使用してKnockout ViewModelを構築できます。

<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>

これは最初のオプションほど賢くありませんが、私はこの方法であまりにも多くのコントロールを放棄しているように感じます。これは、私のKO ViewModelがMVC ViewModelの構造にかなり密接に結合していることを意味します。言うまでもありませんが、これが機能するには、JavaScriptがcshtmlページにある必要があります。最後に、これらのアプローチはどちらも純粋にサーバー側です。 SPIなどの応答性の高いWebページの場合は、クライアント側でより多くのことを実行する必要があります。

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

23
Joel Cochran

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

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

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

8

私のアプローチ:

  • ビューモデルは、サーバー側のコード生成なしで独自の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がないため、UIデータアクセスが含まれます。データベース、データの量などによっては、データの読み込みに時間がかかることがあります。また、コードで問題を明確に分離できます。

7
John Rayner

私が行うことは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>

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

3
Phoenix_uy

@ Html.Rawを使用しているのは、Knockout UIが生成されるまでユーザーがページで実行できる便利なことは何もないため、JSONをページに書き込むことによる追加の初期ダウンロードによる潜在的なわずかなタイムラグがユーザーによってオフセットされないためです。 UIが構築される前に不安な遅延が発生する。私のページに直接ある最初のビューモデルを構築するために使用されるJSONにはまったく問題はありません。

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

3
Tom Hall

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

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

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

2
Steen Tøttrup

古い質問ですが、モデルデータを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データ)を取る必要があります。

0
Michael Fry