Лучшая практика передачи Mvc-модели для KnockoutJS
Я googled вокруг о том, как передать mvc-модель в knockoutjs, и кажется, что есть два пути:
- Использование @Html.Raw(Json.Encode(Model))
- Использование $.get или $.ajax
Какой из способов является наилучшей практикой передачи mvc-модели на knockoutjs? Я знаю, что это зависит от требований, но кажется, что использование $.get более чище по сравнению с методом @Html.Raw.
Ответы
Ответ 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 на конечную точку.