Подтвердить что ты не робот

Лучшая практика передачи Mvc-модели для KnockoutJS

Я googled вокруг о том, как передать mvc-модель в knockoutjs, и кажется, что есть два пути:

  • Использование @Html.Raw(Json.Encode(Model))
  • Использование $.get или $.ajax

Какой из способов является наилучшей практикой передачи mvc-модели на knockoutjs? Я знаю, что это зависит от требований, но кажется, что использование $.get более чище по сравнению с методом @Html.Raw.

4b9b3361

Ответ 1

Я успешно использовал несколько подходов.

В строго типизированном представлении Razor вы можете написать объект JavaScript ViewModel, как и любой другой HTML, вставляя элементы модели во время своей работы. Я нахожу этот klunky, поскольку Razor и JS не играют хорошо вместе с Visual Studio и Intellisense, но даже с кучей красных squigglies результирующий код отлично работает.

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

Этот код может стать уродливым в спешке в зависимости от сложности вашей модели. Как вы упомянули, вы также можете сериализовать объект модели в JSON с помощью Html.Raw(). Если вы поедете по этому маршруту, вы можете использовать его для создания своей ночной модели ViewModel с помощью библиотеки KO Mapping:

<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, вы захотите сделать больше на стороне клиента.

Мое предпочтение заключается в том, чтобы использовать клиентскую часть $.getJSON на стороне JavaScript. В этот момент вы можете обрабатывать возвращаемые данные в свою ViewModel, либо вручную, либо используя библиотеку сопоставления. Если вы возвращаетесь к действиям в своем MVC-контроллере, просто верните действие JsonResult (вместо ActionResult). (Вы также можете создавать похожие материалы с помощью ContentResult). Если вы можете использовать новый MVAP4 WebAPI, эти контроллеры по умолчанию возвратят JSON.

Ответ 2

@Html.Raw(Json.Encode(Model)) используется, когда вы хотите, чтобы данные отправлялись как часть фактической загрузки страницы. Это может привести к тому, что ваша страница займет больше времени для предоставления пользователю, но когда она сделает, все должно быть готово к работе.

$. get или $.ajax вместо этого получат данные во время рендеринга страницы. Это создает отдельный вызов, который приведет к обновлению вашей страницы после ее рендеринга.

Как использовать. Это зависит от того, как выкладывается ваша страница, независимо от того, нужно ли вам иметь все данные для начала и сколько времени требуется, чтобы получить ваши данные и визуализировать вашу страницу.

Ответ 3

Мой подход:

  • Модель просмотра
  • написана в собственном 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. Преимущество заключается в том, что мой пользовательский интерфейс можно быстро обслуживать, потому что нет реального доступа к данным. Загрузка данных может занять некоторое время в зависимости от базы данных, объема данных и т.д. И т.д. Это также дает моему коду очень четкое разделение проблем.

Ответ 4

Я использую @Html.Raw, потому что нет ничего полезного, которое пользователь может сделать на странице до тех пор, пока не будет сгенерирован пользовательский интерфейс Knockout, и любое потенциальное тривиальное временное отставание из-за дополнительной начальной загрузки из записи JSON на страницу компенсируется пользователь не видит задержку задержки до создания пользовательского интерфейса. У меня совсем нет проблемы с JSON, используемым для того, чтобы моя первоначальная модель представления была непосредственно на моей странице.

В тех случаях, когда я делаю повышение эффективности, можно получить любые повторяющиеся ссылочные данные для таких вещей, как опции выбора (списки продуктов и т.д.) в отдельной динамической загрузке script с контроллера MVC, который затем кэшируется браузером. Таким образом, они могут быть повторно использованы в разных моделях просмотра, и для моделей просмотра требуется только сохранить выбранное значение элемента.

Ответ 5

Как вы говорите, это в значительной степени зависит от требований.

Если вы делаете "одностраничное приложение", вы будете делать много вызовов $.get и $.ajax, если вы просто показываете одну страницу, возможно, быстрее модели в Html, сохраняя дополнительный запрос на сервер.

Также зависит от того, сколько кода вы хотите на стороне сервера, если мои приложения нуждаются в API в любом случае, я имею тенденцию повторно использовать API и делать вызовы $.get и $.ajax, если нет, я помещаю модель в Html.

Ответ 6

Что я делаю, это Html.Raw, а затем этот объект js передаю его моей модели jock-нокаута. Что-то вроде этого:

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

Что я делаю.

Ответ 7

Старый вопрос, но я думаю, что у меня есть хорошее опрятное решение для передачи данных модели в модель просмотра KO в многоразовом режиме. Заметьте, я также использую require.js.

Добавьте метод расширения HtmlHelper в .NET:

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 и должен возвращать функцию конструктора для модели представления. Конструктор должен принять один аргумент - данные JSON для модели.

Ответ 8

В моем сознании желательно, чтобы HTML был чистым и чтобы не смешивать встроенные JavaScript и данные.

Я предпочитаю вводить данные с помощью вызова AJAX на конечную точку.