Я работаю над профилем для пользователей на моем веб-сайте ASP.NET MVC. И у меня есть много свойств (флажки, выпадающие списки и т.д.), Например:
Я могу сделать свою собственную модель для обработки всех из них следующим образом:
public class ProfileViewModel
{
public TimeZoneOptions TimeZone { get; set; }
public DstOptions Dst { get; set; } // Daylight Saving Time
public bool EmailSettings1 { get; set; }
public bool EmailSettings2 { get; set; }
// ...
public bool EmailSettings22 { get; set; }
}
Мои свойства модели просмотра не привязаны друг к другу. Поэтому мне не нужно вызывать ModelState.IsValid
. Кажется, моя модель всегда будет действительной.
Если я буду следовать стандартным способам сохранения модели в ASP.NET MVC, это заставит моего клиента дважды щелкнуть:
Но я хочу, чтобы они сделали это одним щелчком мыши. Как на этом скриншоте:
Я хочу, чтобы каждое свойство было отмечено "Изменения сохранены", когда пользователь нажимает на них. И я хочу достичь этого с минимальным количеством кода. Кажется, что это легко сделать с:
или
Но я не могу решить, что лучше. В jQuery я могу напрямую манипулировать с DOM. Но, похоже, с нокаутом он может быть более элегантным, и я могу сделать мой код более удобным.
Я не знаю, как это сделать с нокаутом, может быть какой-то привязкой, необходимой для обновления элемента, когда он сохраняется следующим образом:
<span data-bind="display-when-saved-for-property: EmailSettings1"></span>
???
Возможно, есть и другие способы сделать это. Любая помощь будет высоко оценен.
Я понимаю, что у вас есть список пользовательских настроек, которые будут отображаться как checkbox
или dropdownlist
список.
Если это так, вы правы, что KnockoutJS более изящный способ (у меня была такая же проблема, прежде чем у меня была кнопка сохранения, мне повезло). Посмотрим, что у нас есть:
У вас есть модель с большей частью свойствами bool
, то, без сомнения, вы должны использовать плагин отображения KnockoutJS. Зачем? все, что мы собираемся сделать, это:
view
HTML - разметку в обычном режиме.view
сделайте запрос AJAX, чтобы получить конфигурацию профиля пользователя, а затем используя mapping plugin
преобразования, преобразуйте возвращенные данные в ViewModel
и привяжите его к нашему view
(все это без необходимости писать ViewModel самим, что означает, что если ViewModel на сервере изменилось, нам просто нужно изменить только view
).checkbox
или dropdownlist
добавьте обработчик события change
(используя jQuery).change
просто преобразует нашу привязанную ViewModel
в строку JSON снова, используя mapping plugin
(всего одну строку кода)Чтобы показать сообщение "Изменения сохранены", вы можете просто передать refrence входного сигнала вызова и использовать немного магии jQuery, чтобы добавить ваше сообщение.
Обновить:
Ваш может выглядеть так (или, может быть, лучше моего):
var UserProfile;
$(document).ready(function() {
$('#ViewContainer input:checkbox').change(function (event) {
SaveUserProfile(event);
});
IntializeUserProfile();
});
function IntializeUserProfile() {
// Show spinner
$.ajax({
type: "POST",
url: URL_To_Get_User_Profile,
data: UserId, // in case of you need to pass data.
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
UserProfile = ko.mapping.fromJSON(data); //ko.mapping.fromJS($.parseJSON(msg));
ko.applyBindings(UserProfile, selector);
// Hide Spinner
}
});
}
function SaveUserProfile(event) {
// Show Spinner
var model = ko.toJSON(ko.mapping.toJS(UserProfile));
event = event || window.event;
target = event.target || event.srcElement;
$.ajax({
type: "POST",
url: URL_To_Save_UserProfile,
data: model,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
// Hide Spinner
// here you have the caller input ==>target.
// for example, you can get it parent to append your message
// or just show message in the page as notification.
}
});
}
Я думаю, что это может быть реализовано с нокаутом + jQuery. С нокаутом очень легко создать приложение с изменением макета (как в вашем случае). JQuery в вашем случае требуется для асинхронных запросов.
Итак, viewmodel:
var ViewModel = function(data) {
var self = this;
var _isCurrentSavingProp = null;
self.EmailSettings1 = ko.observable(data.EmailSettings1);
self.IsEmailSettings1Saved = ko.observable();
... another props
self.EmailSettings1.subscribe(function(val) {
isCurrentSavingProp = self.IsEmailSettings1Saved;
self.save();
});
... another subscribers
self.save = function() {
isCurrentSavingProp(false);
$.post(url, ko.toJSON(self), function() {
isCurrentSavingProp(true);
})
}
}
Html:
<span data-bind="visible: IsEmailSettings1Saved" style="display: none"></span>
<input type="checkbox" data-bind="value: EmailSettings1" />
... etc..
Хорошо, что ваша модель должна быть чем-то вроде этого.
public class MyModel
{
public bool? Friends { get; set; }
public bool? Photos { get; set; }
public string Car { get; set; }
}
Ваш метод контроллера принимает экземпляр вашей модели. Пока ваш запрос ajax имеет имя данных, которое соответствует имени свойства в вашей модели, оно будет связываться.
public void UpdateValues(MyModel model)
{
if(model.Friends != null)
{
//Save
}
if (model.Photos != null)
{
//Save
}
if (model.Car != null)
{
//Save
}
}
Допустим, ваша html-разметка похожа на эту
<div id="checkbox-container">
<div>
<label>
<input type="checkbox" name="friends" />
My Friends</label>
</div>
<div>
<label><input type="checkbox" name="photos" />My Photos</label>
</div>
<select id="car-dropdown">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</div>
И вот jQuery....
$('#checkbox-container input:checkbox').change(function () {
//Gets the property name we will bind
var field = $(this).attr("name");
var isChecked = $(this).prop("checked");
var data = {};
data[field] = isChecked;
requestBuilder(data);
});
//New method for our dropdown
$('#car-dropdown').change(function()
{
var data = {};
data['Car'] = $(this).val();
requestBuilder(data);
});
function requestBuilder(data)
{
//Ajax Request
$.ajax({
//Change url to match your controller
url:"/Controller/UpdateValues/",
data:data,
type:"POST",
success:function(response)
{
alert("Change Saved")
}
});
}
Обратите внимание, как мы передаем атрибут Name = "". Это соответствует имени, которое у нас есть в нашей модели, поэтому оно будет связываться :)
Дайте мне знать, если вам нужно, чтобы я расширил любой элемент. Я также создал jsfiddle для кода переднего конца - http://jsfiddle.net/8tKBx/
Удачи!